@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.
- 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
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints'
|
|
1
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
3
3
|
import { Organization, RegisterCode } from '@stamhoofd/models';
|
|
4
|
-
import {RegisterCode as RegisterCodeStruct } from
|
|
4
|
+
import { RegisterCode as RegisterCodeStruct } from '@stamhoofd/structures';
|
|
5
5
|
type Params = { code: string };
|
|
6
6
|
type Query = undefined;
|
|
7
7
|
type Body = undefined;
|
|
8
8
|
type ResponseBody = RegisterCodeStruct;
|
|
9
9
|
|
|
10
10
|
export class CheckRegisterCodeEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
11
|
-
|
|
12
11
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
13
|
-
if (request.method
|
|
12
|
+
if (request.method !== 'GET') {
|
|
14
13
|
return [false];
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
const params = Endpoint.parseParameters(request.url,
|
|
16
|
+
const params = Endpoint.parseParameters(request.url, '/register-code/@code', { code: String });
|
|
18
17
|
|
|
19
18
|
if (params) {
|
|
20
19
|
return [true, params as Params];
|
|
@@ -23,23 +22,22 @@ export class CheckRegisterCodeEndpoint extends Endpoint<Params, Query, Body, Res
|
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
26
|
-
|
|
27
|
-
const code = await RegisterCode.getByID(request.params.code)
|
|
25
|
+
const code = await RegisterCode.getByID(request.params.code);
|
|
28
26
|
if (code) {
|
|
29
27
|
return new Response(RegisterCodeStruct.create({
|
|
30
28
|
code: code.code,
|
|
31
29
|
description: code.description,
|
|
32
30
|
customMessage: code.customMessage,
|
|
33
31
|
organizationName: code.organizationId ? ((await Organization.getByID(code.organizationId))!.name) : null,
|
|
34
|
-
value: code.value
|
|
35
|
-
}))
|
|
32
|
+
value: code.value,
|
|
33
|
+
}));
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
throw new SimpleError({
|
|
39
|
-
code:
|
|
40
|
-
message:
|
|
41
|
-
human:
|
|
42
|
-
field:
|
|
43
|
-
})
|
|
37
|
+
code: 'invalid_code',
|
|
38
|
+
message: 'Invalid code',
|
|
39
|
+
human: 'Deze code is niet geldig',
|
|
40
|
+
field: 'registerCode',
|
|
41
|
+
});
|
|
44
42
|
}
|
|
45
43
|
}
|
|
@@ -1,57 +1,56 @@
|
|
|
1
|
+
import { Request } from '@simonbackx/simple-endpoints';
|
|
2
|
+
import { Address, Country, CreateOrganization, NewUser, Organization as OrganizationStruct, Version } from '@stamhoofd/structures';
|
|
1
3
|
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
+
import { testServer } from '../../../../tests/helpers/TestServer';
|
|
5
|
+
import { CreateOrganizationEndpoint } from './CreateOrganizationEndpoint';
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
import { CreateOrganizationEndpoint } from "./CreateOrganizationEndpoint";
|
|
7
|
-
|
|
8
|
-
describe("Endpoint.CreateOrganization", () => {
|
|
7
|
+
describe('Endpoint.CreateOrganization', () => {
|
|
9
8
|
// Test endpoint
|
|
10
9
|
const endpoint = new CreateOrganizationEndpoint();
|
|
11
10
|
|
|
12
|
-
test(
|
|
13
|
-
const r = Request.buildJson(
|
|
11
|
+
test('Can create a new organization', async () => {
|
|
12
|
+
const r = Request.buildJson('POST', `/v${Version}/organizations`, 'todo-host.be', CreateOrganization.create({
|
|
14
13
|
organization: OrganizationStruct.create({
|
|
15
|
-
name:
|
|
16
|
-
uri:
|
|
14
|
+
name: 'My endpoint test organization',
|
|
15
|
+
uri: 'my-endpoint-test-organization',
|
|
17
16
|
address: Address.create({
|
|
18
|
-
street:
|
|
19
|
-
number:
|
|
20
|
-
postalCode:
|
|
21
|
-
city:
|
|
22
|
-
country: Country.Belgium
|
|
17
|
+
street: 'My street',
|
|
18
|
+
number: '1',
|
|
19
|
+
postalCode: '9000',
|
|
20
|
+
city: 'Gent',
|
|
21
|
+
country: Country.Belgium,
|
|
23
22
|
}),
|
|
24
|
-
|
|
23
|
+
|
|
25
24
|
}),
|
|
26
25
|
user: NewUser.create({
|
|
27
|
-
email:
|
|
28
|
-
password:
|
|
26
|
+
email: 'voorbeeld@stamhoofd.be',
|
|
27
|
+
password: 'My user password',
|
|
29
28
|
}),
|
|
30
|
-
}).encode({version: Version}));
|
|
29
|
+
}).encode({ version: Version }));
|
|
31
30
|
|
|
32
31
|
const response = await testServer.test(endpoint, r);
|
|
33
32
|
expect(response.body.token).not.toBeEmpty();
|
|
34
33
|
});
|
|
35
34
|
|
|
36
|
-
test(
|
|
37
|
-
const r = Request.buildJson(
|
|
35
|
+
test('Creating an organization with an in-use URI throws', async () => {
|
|
36
|
+
const r = Request.buildJson('POST', `/v${Version}/organizations`, 'todo-host.be', CreateOrganization.create({
|
|
38
37
|
organization: OrganizationStruct.create({
|
|
39
|
-
name:
|
|
40
|
-
uri:
|
|
38
|
+
name: 'My endpoint test organization',
|
|
39
|
+
uri: 'my-endpoint-test-organization',
|
|
41
40
|
address: Address.create({
|
|
42
|
-
street:
|
|
43
|
-
number:
|
|
44
|
-
postalCode:
|
|
45
|
-
city:
|
|
46
|
-
country: Country.Belgium
|
|
41
|
+
street: 'My street',
|
|
42
|
+
number: '1',
|
|
43
|
+
postalCode: '9000',
|
|
44
|
+
city: 'Gent',
|
|
45
|
+
country: Country.Belgium,
|
|
47
46
|
}),
|
|
48
|
-
|
|
47
|
+
|
|
49
48
|
}),
|
|
50
49
|
user: NewUser.create({
|
|
51
|
-
email:
|
|
52
|
-
password:
|
|
53
|
-
})
|
|
54
|
-
}).encode({version: Version}));
|
|
50
|
+
email: 'voorbeeld@stamhoofd.be',
|
|
51
|
+
password: 'My user password',
|
|
52
|
+
}),
|
|
53
|
+
}).encode({ version: Version }));
|
|
55
54
|
|
|
56
55
|
await expect(testServer.test(endpoint, r)).rejects.toThrow(/name/);
|
|
57
56
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Decoder } from '@simonbackx/simple-encoding';
|
|
2
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
2
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
4
|
import { EmailVerificationCode, Organization, User } from '@stamhoofd/models';
|
|
5
|
-
import { CreateOrganization, PermissionLevel, Permissions, SignupResponse, UserPermissions } from
|
|
6
|
-
import { Formatter } from
|
|
5
|
+
import { CreateOrganization, PermissionLevel, Permissions, SignupResponse, UserPermissions } from '@stamhoofd/structures';
|
|
6
|
+
import { Formatter } from '@stamhoofd/utility';
|
|
7
7
|
|
|
8
8
|
type Params = Record<string, never>;
|
|
9
9
|
type Query = undefined;
|
|
@@ -14,11 +14,11 @@ export class CreateOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
14
14
|
bodyDecoder = CreateOrganization as Decoder<CreateOrganization>;
|
|
15
15
|
|
|
16
16
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
17
|
-
if (request.method
|
|
17
|
+
if (request.method !== 'POST') {
|
|
18
18
|
return [false];
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const params = Endpoint.parseParameters(request.url,
|
|
21
|
+
const params = Endpoint.parseParameters(request.url, '/organizations', {});
|
|
22
22
|
|
|
23
23
|
if (params) {
|
|
24
24
|
return [true, params as Params];
|
|
@@ -29,48 +29,48 @@ export class CreateOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
29
29
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
30
30
|
if (STAMHOOFD.userMode === 'platform') {
|
|
31
31
|
throw new SimpleError({
|
|
32
|
-
code:
|
|
33
|
-
message:
|
|
34
|
-
human:
|
|
35
|
-
})
|
|
32
|
+
code: 'invalid_field',
|
|
33
|
+
message: 'Not allowed',
|
|
34
|
+
human: 'Je kan geen vereniging aanmaken',
|
|
35
|
+
});
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
if (request.body.organization.name.length < 4) {
|
|
39
39
|
if (request.body.organization.name.length == 0) {
|
|
40
40
|
throw new SimpleError({
|
|
41
|
-
code:
|
|
42
|
-
message:
|
|
43
|
-
human:
|
|
44
|
-
field:
|
|
45
|
-
})
|
|
41
|
+
code: 'invalid_field',
|
|
42
|
+
message: 'Should not be empty',
|
|
43
|
+
human: 'Je bent de naam van je organisatie vergeten in te vullen',
|
|
44
|
+
field: 'organization.name',
|
|
45
|
+
});
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
throw new SimpleError({
|
|
49
|
-
code:
|
|
50
|
-
message:
|
|
51
|
-
human:
|
|
52
|
-
field:
|
|
53
|
-
})
|
|
49
|
+
code: 'invalid_field',
|
|
50
|
+
message: 'Field is too short',
|
|
51
|
+
human: 'Kijk de naam van je organisatie na, deze is te kort. Vul eventueel aan met de gemeente.',
|
|
52
|
+
field: 'organization.name',
|
|
53
|
+
});
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
const uri = Formatter.slug(request.body.organization.name);
|
|
57
57
|
|
|
58
58
|
if (uri.length > 100) {
|
|
59
59
|
throw new SimpleError({
|
|
60
|
-
code:
|
|
61
|
-
message:
|
|
62
|
-
human:
|
|
63
|
-
field:
|
|
64
|
-
})
|
|
60
|
+
code: 'invalid_field',
|
|
61
|
+
message: 'Field is too long',
|
|
62
|
+
human: 'De naam van de vereniging is te lang. Probeer de naam wat te verkorten en probeer opnieuw.',
|
|
63
|
+
field: 'organization.name',
|
|
64
|
+
});
|
|
65
65
|
}
|
|
66
66
|
const alreadyExists = await Organization.getByURI(uri);
|
|
67
67
|
|
|
68
68
|
if (alreadyExists) {
|
|
69
69
|
throw new SimpleError({
|
|
70
|
-
code:
|
|
71
|
-
message:
|
|
72
|
-
human:
|
|
73
|
-
field:
|
|
70
|
+
code: 'name_taken',
|
|
71
|
+
message: 'An organization with the same name already exists',
|
|
72
|
+
human: 'Er bestaat al een vereniging met dezelfde naam. Voeg bijvoorbeeld de naam van je gemeente toe.',
|
|
73
|
+
field: 'name',
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
76
|
|
|
@@ -84,61 +84,52 @@ export class CreateOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
84
84
|
// let registerCodeModels: Model[] = []
|
|
85
85
|
// let delayEmails: EmailInterfaceBase[] = []
|
|
86
86
|
|
|
87
|
-
//if (request.body.registerCode) {
|
|
87
|
+
// if (request.body.registerCode) {
|
|
88
88
|
// const applied = await RegisterCode.applyRegisterCode(organization, request.body.registerCode)
|
|
89
89
|
// registerCodeModels = applied.models
|
|
90
90
|
// delayEmails = applied.emails
|
|
91
|
-
//}
|
|
91
|
+
// }
|
|
92
92
|
|
|
93
93
|
organization.uri = uri;
|
|
94
|
-
organization.meta = request.body.organization.meta
|
|
95
|
-
organization.address = request.body.organization.address
|
|
96
|
-
organization.privateMeta.acquisitionTypes = request.body.organization.privateMeta?.acquisitionTypes ?? []
|
|
94
|
+
organization.meta = request.body.organization.meta;
|
|
95
|
+
organization.address = request.body.organization.address;
|
|
96
|
+
organization.privateMeta.acquisitionTypes = request.body.organization.privateMeta?.acquisitionTypes ?? [];
|
|
97
97
|
|
|
98
98
|
try {
|
|
99
99
|
await organization.save();
|
|
100
|
-
}
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
101
102
|
console.error(e);
|
|
102
103
|
throw new SimpleError({
|
|
103
|
-
code:
|
|
104
|
-
message:
|
|
105
|
-
statusCode: 500
|
|
104
|
+
code: 'creating_organization',
|
|
105
|
+
message: 'Something went wrong while creating the organization. Please try again later or contact us.',
|
|
106
|
+
statusCode: 500,
|
|
106
107
|
});
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
const user = await User.register(
|
|
110
111
|
organization,
|
|
111
|
-
request.body.user
|
|
112
|
+
request.body.user,
|
|
112
113
|
);
|
|
113
114
|
if (!user) {
|
|
114
115
|
// This user already exists, well that is pretty impossible
|
|
115
116
|
throw new SimpleError({
|
|
116
|
-
code:
|
|
117
|
-
message:
|
|
118
|
-
statusCode: 500
|
|
117
|
+
code: 'creating_user',
|
|
118
|
+
message: 'Something went wrong while creating the user. Please contact us to resolve this issue.',
|
|
119
|
+
statusCode: 500,
|
|
119
120
|
});
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
// Should prevent this extra save
|
|
123
|
-
user.permissions = UserPermissions.create({})
|
|
124
|
-
user.permissions.organizationPermissions.set(organization.id, Permissions.create({ level: PermissionLevel.Full }))
|
|
125
|
-
await user.save()
|
|
124
|
+
user.permissions = UserPermissions.create({});
|
|
125
|
+
user.permissions.organizationPermissions.set(organization.id, Permissions.create({ level: PermissionLevel.Full }));
|
|
126
|
+
await user.save();
|
|
126
127
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// }
|
|
130
|
-
|
|
131
|
-
const code = await EmailVerificationCode.createFor(user, user.email)
|
|
132
|
-
code.send(user, organization, request.i18n)
|
|
133
|
-
|
|
134
|
-
// for (const email of delayEmails) {
|
|
135
|
-
// Email.sendInternal(email, organization.i18n)
|
|
136
|
-
// }
|
|
128
|
+
const code = await EmailVerificationCode.createFor(user, user.email);
|
|
129
|
+
code.send(user, organization, request.i18n).catch(console.error);
|
|
137
130
|
|
|
138
131
|
return new Response(SignupResponse.create({
|
|
139
|
-
token: code.token
|
|
132
|
+
token: code.token,
|
|
140
133
|
}));
|
|
141
134
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
135
|
}
|
|
@@ -1,52 +1,51 @@
|
|
|
1
|
-
import { Request } from
|
|
1
|
+
import { Request } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { GroupFactory, OrganizationFactory } from '@stamhoofd/models';
|
|
3
3
|
import { Organization } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
|
-
import { testServer } from
|
|
5
|
+
import { testServer } from '../../../../tests/helpers/TestServer';
|
|
6
6
|
import { GetOrganizationFromDomainEndpoint } from './GetOrganizationFromDomainEndpoint';
|
|
7
7
|
|
|
8
|
-
describe(
|
|
8
|
+
describe('Endpoint.GetOrganizationFromDomain', () => {
|
|
9
9
|
// Test endpoint
|
|
10
10
|
const endpoint = new GetOrganizationFromDomainEndpoint();
|
|
11
11
|
|
|
12
|
-
test(
|
|
13
|
-
const organization = await new OrganizationFactory({}).create()
|
|
14
|
-
const groups = await new GroupFactory({ organization }).createMultiple(2)
|
|
12
|
+
test('Get organization from default uri', async () => {
|
|
13
|
+
const organization = await new OrganizationFactory({}).create();
|
|
14
|
+
const groups = await new GroupFactory({ organization }).createMultiple(2);
|
|
15
15
|
|
|
16
|
-
const r = Request.buildJson(
|
|
16
|
+
const r = Request.buildJson('GET', '/v2/organization-from-domain');
|
|
17
17
|
r.query = {
|
|
18
|
-
|
|
19
|
-
}
|
|
18
|
+
domain: organization.uri + '.stamhoofd.dev',
|
|
19
|
+
};
|
|
20
20
|
|
|
21
21
|
const response = await testServer.test(endpoint, r);
|
|
22
22
|
expect(response.body).toBeDefined();
|
|
23
23
|
|
|
24
24
|
if (!(response.body instanceof Organization)) {
|
|
25
|
-
throw new Error(
|
|
25
|
+
throw new Error('Expected Organization');
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
expect(response.body.id).toEqual(organization.id)
|
|
29
|
-
expect(response.body.groups.map(g => g.id).sort()).toEqual(groups.map(g => g.id).sort())
|
|
28
|
+
expect(response.body.id).toEqual(organization.id);
|
|
29
|
+
expect(response.body.groups.map(g => g.id).sort()).toEqual(groups.map(g => g.id).sort());
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
test(
|
|
33
|
-
const organization = await new OrganizationFactory({ domain:
|
|
34
|
-
const groups = await new GroupFactory({ organization }).createMultiple(2)
|
|
32
|
+
test('Get organization from custom domain', async () => {
|
|
33
|
+
const organization = await new OrganizationFactory({ domain: 'inschrijven.mijnscouts.be' }).create();
|
|
34
|
+
const groups = await new GroupFactory({ organization }).createMultiple(2);
|
|
35
35
|
|
|
36
|
-
const r = Request.buildJson(
|
|
36
|
+
const r = Request.buildJson('GET', '/v2/organization-from-domain');
|
|
37
37
|
r.query = {
|
|
38
|
-
|
|
39
|
-
}
|
|
38
|
+
domain: 'inschrijven.mijnscouts.be',
|
|
39
|
+
};
|
|
40
40
|
|
|
41
41
|
const response = await testServer.test(endpoint, r);
|
|
42
42
|
expect(response.body).toBeDefined();
|
|
43
43
|
|
|
44
44
|
if (!(response.body instanceof Organization)) {
|
|
45
|
-
throw new Error(
|
|
45
|
+
throw new Error('Expected Organization');
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
expect(response.body.id).toEqual(organization.id)
|
|
49
|
-
expect(response.body.groups.map(g => g.id).sort()).toEqual(groups.map(g => g.id).sort())
|
|
48
|
+
expect(response.body.id).toEqual(organization.id);
|
|
49
|
+
expect(response.body.groups.map(g => g.id).sort()).toEqual(groups.map(g => g.id).sort());
|
|
50
50
|
});
|
|
51
|
-
|
|
52
51
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { AutoEncoder, Decoder, field, StringDecoder } from
|
|
2
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
1
|
+
import { AutoEncoder, Decoder, field, StringDecoder } from '@simonbackx/simple-encoding';
|
|
2
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
4
|
import { Organization } from '@stamhoofd/models';
|
|
5
|
-
import { Organization as OrganizationStruct } from
|
|
6
|
-
import { GoogleTranslateHelper } from
|
|
7
|
-
import { AuthenticatedStructures } from
|
|
5
|
+
import { Organization as OrganizationStruct } from '@stamhoofd/structures';
|
|
6
|
+
import { GoogleTranslateHelper } from '@stamhoofd/utility';
|
|
7
|
+
import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
|
|
8
8
|
type Params = Record<string, never>;
|
|
9
9
|
|
|
10
10
|
class Query extends AutoEncoder {
|
|
@@ -12,7 +12,7 @@ class Query extends AutoEncoder {
|
|
|
12
12
|
domain: string;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
type Body = undefined
|
|
15
|
+
type Body = undefined;
|
|
16
16
|
type ResponseBody = OrganizationStruct;
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -20,15 +20,15 @@ type ResponseBody = OrganizationStruct;
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
export class GetOrganizationFromDomainEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
23
|
-
queryDecoder = Query as Decoder<Query
|
|
24
|
-
registrationDomains = [...
|
|
23
|
+
queryDecoder = Query as Decoder<Query>;
|
|
24
|
+
registrationDomains = [...new Set(Object.values(STAMHOOFD.domains.registration ?? {}))];
|
|
25
25
|
|
|
26
26
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
27
|
-
if (request.method
|
|
27
|
+
if (request.method !== 'GET') {
|
|
28
28
|
return [false];
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const params = Endpoint.parseParameters(request.url,
|
|
31
|
+
const params = Endpoint.parseParameters(request.url, '/organization-from-domain', {});
|
|
32
32
|
|
|
33
33
|
if (params) {
|
|
34
34
|
return [true, params as Params];
|
|
@@ -38,28 +38,28 @@ export class GetOrganizationFromDomainEndpoint extends Endpoint<Params, Query, B
|
|
|
38
38
|
|
|
39
39
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
40
40
|
// Clean up google translate domains -> make sure we can translate register pages
|
|
41
|
-
request.query.domain = GoogleTranslateHelper.getDomainFromTranslateDomain(request.query.domain)
|
|
41
|
+
request.query.domain = GoogleTranslateHelper.getDomainFromTranslateDomain(request.query.domain);
|
|
42
42
|
|
|
43
43
|
for (const domain of this.registrationDomains) {
|
|
44
|
-
if (request.query.domain.endsWith(
|
|
45
|
-
const strippped = request.query.domain.substr(0, request.query.domain.length - (
|
|
46
|
-
if (strippped.includes(
|
|
44
|
+
if (request.query.domain.endsWith('.' + domain)) {
|
|
45
|
+
const strippped = request.query.domain.substr(0, request.query.domain.length - ('.' + domain).length);
|
|
46
|
+
if (strippped.includes('.')) {
|
|
47
47
|
throw new SimpleError({
|
|
48
|
-
code:
|
|
49
|
-
message:
|
|
50
|
-
statusCode: 404
|
|
51
|
-
})
|
|
48
|
+
code: 'invalid_domain',
|
|
49
|
+
message: 'This domain format is not supported',
|
|
50
|
+
statusCode: 404,
|
|
51
|
+
});
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
// Search for the URI
|
|
55
|
-
const organization = await Organization.getByURI(strippped)
|
|
55
|
+
const organization = await Organization.getByURI(strippped);
|
|
56
56
|
|
|
57
57
|
if (!organization) {
|
|
58
58
|
throw new SimpleError({
|
|
59
|
-
code:
|
|
60
|
-
message:
|
|
61
|
-
statusCode: 404
|
|
62
|
-
})
|
|
59
|
+
code: 'unknown_organization',
|
|
60
|
+
message: 'No organization registered with this domain name',
|
|
61
|
+
statusCode: 404,
|
|
62
|
+
});
|
|
63
63
|
}
|
|
64
64
|
return new Response(await AuthenticatedStructures.organization(organization));
|
|
65
65
|
}
|
|
@@ -67,14 +67,14 @@ export class GetOrganizationFromDomainEndpoint extends Endpoint<Params, Query, B
|
|
|
67
67
|
|
|
68
68
|
// Check if we have an organization with a custom domain name
|
|
69
69
|
|
|
70
|
-
const organization = await Organization.getByRegisterDomain(request.query.domain)
|
|
70
|
+
const organization = await Organization.getByRegisterDomain(request.query.domain);
|
|
71
71
|
|
|
72
72
|
if (!organization) {
|
|
73
73
|
throw new SimpleError({
|
|
74
|
-
code:
|
|
75
|
-
message:
|
|
76
|
-
statusCode: 404
|
|
77
|
-
})
|
|
74
|
+
code: 'unknown_organization',
|
|
75
|
+
message: 'No organization registered with this domain name',
|
|
76
|
+
statusCode: 404,
|
|
77
|
+
});
|
|
78
78
|
}
|
|
79
79
|
return new Response(await AuthenticatedStructures.organization(organization));
|
|
80
80
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { AutoEncoder, Decoder, field, StringDecoder } from
|
|
2
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
1
|
+
import { AutoEncoder, Decoder, field, StringDecoder } from '@simonbackx/simple-encoding';
|
|
2
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
4
|
import { Organization } from '@stamhoofd/models';
|
|
5
|
-
import { Organization as OrganizationStruct } from
|
|
6
|
-
import { GoogleTranslateHelper } from
|
|
7
|
-
import { AuthenticatedStructures } from
|
|
5
|
+
import { Organization as OrganizationStruct } from '@stamhoofd/structures';
|
|
6
|
+
import { GoogleTranslateHelper } from '@stamhoofd/utility';
|
|
7
|
+
import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
|
|
8
8
|
type Params = Record<string, never>;
|
|
9
9
|
|
|
10
10
|
class Query extends AutoEncoder {
|
|
@@ -12,7 +12,7 @@ class Query extends AutoEncoder {
|
|
|
12
12
|
uri: string;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
type Body = undefined
|
|
15
|
+
type Body = undefined;
|
|
16
16
|
type ResponseBody = OrganizationStruct;
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -20,14 +20,14 @@ type ResponseBody = OrganizationStruct;
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
export class GetOrganizationFromUriEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
23
|
-
queryDecoder = Query as Decoder<Query
|
|
23
|
+
queryDecoder = Query as Decoder<Query>;
|
|
24
24
|
|
|
25
25
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
26
|
-
if (request.method
|
|
26
|
+
if (request.method !== 'GET') {
|
|
27
27
|
return [false];
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
const params = Endpoint.parseParameters(request.url,
|
|
30
|
+
const params = Endpoint.parseParameters(request.url, '/organization-from-uri', {});
|
|
31
31
|
|
|
32
32
|
if (params) {
|
|
33
33
|
return [true, params as Params];
|
|
@@ -36,22 +36,22 @@ export class GetOrganizationFromUriEndpoint extends Endpoint<Params, Query, Body
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
39
|
-
const organization = await Organization.getByURI(request.query.uri)
|
|
39
|
+
const organization = await Organization.getByURI(request.query.uri);
|
|
40
40
|
|
|
41
41
|
if (!organization) {
|
|
42
42
|
throw new SimpleError({
|
|
43
|
-
code:
|
|
44
|
-
message:
|
|
45
|
-
statusCode: 404
|
|
46
|
-
})
|
|
43
|
+
code: 'unknown_organization',
|
|
44
|
+
message: 'No organization registered with this uri',
|
|
45
|
+
statusCode: 404,
|
|
46
|
+
});
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if (!organization.active) {
|
|
50
50
|
throw new SimpleError({
|
|
51
|
-
code:
|
|
52
|
-
message:
|
|
53
|
-
statusCode: 404
|
|
54
|
-
})
|
|
51
|
+
code: 'archived_organization',
|
|
52
|
+
message: 'This organization has been archived',
|
|
53
|
+
statusCode: 404,
|
|
54
|
+
});
|
|
55
55
|
}
|
|
56
56
|
return new Response(await AuthenticatedStructures.organization(organization));
|
|
57
57
|
}
|