@stamhoofd/backend 2.39.0 → 2.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/eslint.config.mjs +5 -0
- package/index.ts +81 -74
- package/jest.config.cjs +10 -0
- package/migrations.ts +16 -14
- package/package.json +11 -11
- package/src/crons/clear-excel-cache.test.ts +48 -50
- package/src/crons/clear-excel-cache.ts +18 -18
- package/src/crons/setup-steps.ts +2 -2
- package/src/crons.ts +325 -306
- package/src/decoders/StringArrayDecoder.ts +7 -7
- package/src/decoders/StringNullableDecoder.ts +1 -2
- package/src/email-recipient-loaders/members.ts +22 -22
- package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +8 -9
- package/src/endpoints/admin/memberships/GetChargeMembershipsSummaryEndpoint.ts +39 -40
- package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +8 -8
- package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +44 -45
- package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +58 -57
- package/src/endpoints/auth/CreateAdminEndpoint.ts +48 -45
- package/src/endpoints/auth/CreateTokenEndpoint.test.ts +31 -31
- package/src/endpoints/auth/CreateTokenEndpoint.ts +146 -147
- package/src/endpoints/auth/DeleteTokenEndpoint.ts +7 -7
- package/src/endpoints/auth/DeleteUserEndpoint.ts +15 -15
- package/src/endpoints/auth/ForgotPasswordEndpoint.ts +17 -18
- package/src/endpoints/auth/GetOtherUserEndpoint.ts +9 -10
- package/src/endpoints/auth/GetUserEndpoint.test.ts +32 -35
- package/src/endpoints/auth/GetUserEndpoint.ts +5 -6
- package/src/endpoints/auth/PatchApiUserEndpoint.ts +35 -33
- package/src/endpoints/auth/PatchUserEndpoint.ts +55 -52
- package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +9 -9
- package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +8 -8
- package/src/endpoints/auth/SignupEndpoint.ts +37 -36
- package/src/endpoints/auth/VerifyEmailEndpoint.ts +29 -28
- package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +33 -33
- package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +7 -7
- package/src/endpoints/global/caddy/CheckDomainCertEndpoint.ts +37 -37
- package/src/endpoints/global/email/CreateEmailEndpoint.ts +30 -30
- package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +13 -13
- package/src/endpoints/global/email/GetEmailEndpoint.ts +13 -13
- package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +16 -16
- package/src/endpoints/global/email/PatchEmailEndpoint.ts +25 -25
- package/src/endpoints/global/events/GetEventsEndpoint.ts +43 -44
- package/src/endpoints/global/events/PatchEventsEndpoint.ts +127 -172
- package/src/endpoints/global/files/ExportToExcelEndpoint.ts +49 -50
- package/src/endpoints/global/files/GetFileCache.ts +13 -13
- package/src/endpoints/global/files/UploadFile.ts +51 -54
- package/src/endpoints/global/files/UploadImage.ts +53 -53
- package/src/endpoints/global/groups/GetGroupsEndpoint.ts +25 -25
- package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +24 -23
- package/src/endpoints/global/members/GetMembersCountEndpoint.ts +8 -8
- package/src/endpoints/global/members/GetMembersEndpoint.ts +105 -102
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +240 -239
- package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +12 -14
- package/src/endpoints/global/organizations/CreateOrganizationEndpoint.test.ts +32 -33
- package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +48 -57
- package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.test.ts +21 -22
- package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +28 -28
- package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +18 -18
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +20 -20
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +17 -17
- package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +81 -75
- package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +14 -14
- package/src/endpoints/global/platform/GetPlatformEnpoint.ts +11 -11
- package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +71 -68
- package/src/endpoints/global/registration/GetPaymentRegistrations.ts +27 -27
- package/src/endpoints/global/registration/GetUserBillingStatusEndpoint.ts +30 -30
- package/src/endpoints/global/registration/GetUserDetailedBillingStatusEndpoint.ts +34 -34
- package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +26 -26
- package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +12 -12
- package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +90 -90
- package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +118 -121
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +362 -350
- package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +8 -9
- package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +21 -21
- package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +65 -65
- package/src/endpoints/organization/dashboard/billing/GetOrganizationBillingStatusEndpoint.ts +9 -9
- package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedBillingStatusEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +17 -17
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +21 -21
- package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +15 -15
- package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +52 -52
- package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplateEndpoint.ts +37 -37
- package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/email/EmailEndpoint.ts +113 -112
- package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +29 -29
- package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +48 -47
- package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +22 -21
- package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +13 -14
- package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +12 -13
- package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +24 -24
- package/src/endpoints/organization/dashboard/nolt/CreateNoltTokenEndpoint.ts +10 -12
- package/src/endpoints/organization/dashboard/organization/GetOrganizationArchivedGroups.ts +14 -14
- package/src/endpoints/organization/dashboard/organization/GetOrganizationDeletedGroups.ts +13 -13
- package/src/endpoints/organization/dashboard/organization/GetOrganizationSSOEndpoint.ts +12 -12
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +120 -124
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +172 -173
- package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +88 -89
- package/src/endpoints/organization/dashboard/organization/SetOrganizationSSOEndpoint.ts +12 -12
- package/src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint.ts +17 -17
- package/src/endpoints/organization/dashboard/payments/GetPaymentsCountEndpoint.ts +8 -8
- package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +66 -67
- package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +47 -47
- package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +93 -91
- package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +16 -17
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +170 -167
- package/src/endpoints/organization/dashboard/registration-periods/SetupStepReviewEndpoint.ts +25 -24
- package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +22 -23
- package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +22 -22
- package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +17 -18
- package/src/endpoints/organization/dashboard/stripe/GetStripeAccountsEndpoint.ts +8 -9
- package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +17 -18
- package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +14 -15
- package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +19 -19
- package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +19 -19
- package/src/endpoints/organization/dashboard/users/GetApiUsersEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +12 -12
- package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +103 -100
- package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +11 -12
- package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +15 -15
- package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +23 -23
- package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +54 -52
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +84 -81
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +120 -111
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +24 -24
- package/src/endpoints/organization/dashboard/webshops/VerifyWebshopDomainEndpoint.ts +18 -18
- package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +141 -130
- package/src/endpoints/organization/shared/GetDocumentHtml.ts +25 -25
- package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +18 -18
- package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +36 -37
- package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +9 -9
- package/src/endpoints/organization/shared/auth/OpenIDConnectCallbackEndpoint.ts +11 -11
- package/src/endpoints/organization/shared/auth/OpenIDConnectStartEndpoint.ts +28 -27
- package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +20 -20
- package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +22 -22
- package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +14 -14
- package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +57 -56
- package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +65 -66
- package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +18 -17
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +124 -128
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +154 -145
- package/src/excel-loaders/members.ts +102 -103
- package/src/excel-loaders/payments.ts +155 -156
- package/src/helpers/AddressValidator.test.ts +32 -32
- package/src/helpers/AddressValidator.ts +128 -122
- package/src/helpers/AdminPermissionChecker.ts +339 -236
- package/src/helpers/AuthenticatedStructures.ts +233 -134
- package/src/helpers/BuckarooHelper.ts +134 -134
- package/src/helpers/CheckSettlements.ts +94 -88
- package/src/helpers/Context.ts +87 -86
- package/src/helpers/CookieHelper.ts +23 -22
- package/src/helpers/EmailResumer.ts +10 -10
- package/src/helpers/FileCache.ts +62 -62
- package/src/helpers/ForwardHandler.test.ts +122 -124
- package/src/helpers/ForwardHandler.ts +76 -70
- package/src/helpers/MemberUserSyncer.ts +101 -96
- package/src/helpers/MembershipCharger.ts +69 -69
- package/src/helpers/MembershipHelper.ts +11 -12
- package/src/helpers/OpenIDConnectHelper.ts +85 -82
- package/src/helpers/PeriodHelper.ts +65 -70
- package/src/helpers/StripeHelper.ts +146 -137
- package/src/helpers/StripePayoutChecker.ts +51 -52
- package/src/helpers/ViesHelper.ts +46 -44
- package/src/helpers/fetchToAsyncIterator.ts +14 -14
- package/src/helpers/xlsxAddressTransformerColumnFactory.ts +50 -52
- package/src/middleware/ContextMiddleware.ts +5 -5
- package/src/migrations/1646578856-validate-addresses.ts +6 -9
- package/src/seeds/0000000000-example.ts +3 -5
- package/src/seeds/1715028563-user-permissions.ts +16 -18
- package/src/seeds/1722256498-group-update-occupancy.ts +12 -12
- package/src/seeds/1722344162-sync-member-users.ts +14 -15
- package/src/seeds/1722344162-update-membership.ts +6 -6
- package/src/seeds/1726055544-balance-item-paid.ts +4 -4
- package/src/seeds/1726055545-balance-item-pending.ts +4 -4
- package/src/seeds/1726494419-update-cached-outstanding-balance.ts +16 -16
- package/src/seeds/1726494420-update-cached-outstanding-balance-from-items.ts +12 -12
- package/src/seeds/1726572303-schedule-stock-updates.ts +12 -12
- package/src/seeds/1726847064-setup-steps.ts +16 -0
- package/src/sql-filters/balance-item-payments.ts +7 -7
- package/src/sql-filters/events.ts +14 -14
- package/src/sql-filters/members.ts +96 -96
- package/src/sql-filters/organizations.ts +139 -75
- package/src/sql-filters/payments.ts +28 -28
- package/src/sql-filters/registrations.ts +14 -14
- package/src/sql-sorters/events.ts +25 -25
- package/src/sql-sorters/members.ts +26 -26
- package/src/sql-sorters/organizations.ts +36 -36
- package/src/sql-sorters/payments.ts +26 -26
- package/tests/e2e/stock.test.ts +616 -621
- package/tests/e2e/tickets.test.ts +255 -260
- package/tests/helpers/StripeMocker.ts +177 -179
- package/tests/helpers/TestServer.ts +9 -9
- package/tests/jest.global.setup.ts +14 -13
- package/tests/jest.setup.ts +33 -32
- package/.eslintrc.js +0 -61
- package/jest.config.js +0 -11
- package/src/helpers/SetupStepsUpdater.ts +0 -359
- 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 =
|
|
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
|
|
2
|
-
import { isSimpleError, isSimpleErrors, SimpleError } from
|
|
3
|
-
import { Organization, Token, User } from
|
|
4
|
-
import { LoginProviderType, OpenIDClientConfiguration, Token as TokenStruct } from
|
|
5
|
-
import crypto from
|
|
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
|
|
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(
|
|
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,
|
|
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,
|
|
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
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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(
|
|
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:
|
|
171
|
-
statusCode: 400
|
|
172
|
-
})
|
|
171
|
+
message: 'Missing name',
|
|
172
|
+
statusCode: 400,
|
|
173
|
+
});
|
|
173
174
|
}
|
|
174
175
|
|
|
175
|
-
let firstName = claims.name.split(
|
|
176
|
-
let lastName = claims.name.split(
|
|
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:
|
|
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:
|
|
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:
|
|
227
|
-
statusCode: 500
|
|
228
|
-
})
|
|
227
|
+
message: 'Failed to create user',
|
|
228
|
+
statusCode: 500,
|
|
229
|
+
});
|
|
229
230
|
}
|
|
230
|
-
}
|
|
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:
|
|
247
|
-
message:
|
|
248
|
-
human:
|
|
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(
|
|
258
|
-
redirectUri.searchParams.set(
|
|
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
|
-
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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(
|
|
277
|
-
redirectUri.searchParams.set(
|
|
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
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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:
|
|
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 =
|
|
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:
|
|
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 =
|
|
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:
|
|
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
|
}
|