@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,8 +1,8 @@
|
|
|
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, Token, User } from '@stamhoofd/models';
|
|
5
|
-
import { Token as TokenStruct, VerifyEmailRequest } from
|
|
5
|
+
import { Token as TokenStruct, VerifyEmailRequest } from '@stamhoofd/structures';
|
|
6
6
|
|
|
7
7
|
import { Context } from '../../helpers/Context';
|
|
8
8
|
|
|
@@ -15,11 +15,11 @@ export class VerifyEmailEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
15
15
|
bodyDecoder = VerifyEmailRequest as Decoder<VerifyEmailRequest>;
|
|
16
16
|
|
|
17
17
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
18
|
-
if (request.method
|
|
18
|
+
if (request.method !== 'POST') {
|
|
19
19
|
return [false];
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const params = Endpoint.parseParameters(request.url,
|
|
22
|
+
const params = Endpoint.parseParameters(request.url, '/verify-email', {});
|
|
23
23
|
|
|
24
24
|
if (params) {
|
|
25
25
|
return [true, params as Params];
|
|
@@ -30,54 +30,55 @@ export class VerifyEmailEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
30
30
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
31
31
|
const organization = await Context.setOptionalOrganizationScope();
|
|
32
32
|
|
|
33
|
-
const code = await EmailVerificationCode.verify(organization?.id ?? null, request.body.token, request.body.code)
|
|
33
|
+
const code = await EmailVerificationCode.verify(organization?.id ?? null, request.body.token, request.body.code);
|
|
34
34
|
|
|
35
35
|
if (!code) {
|
|
36
36
|
throw new SimpleError({
|
|
37
|
-
code:
|
|
38
|
-
message:
|
|
39
|
-
human:
|
|
40
|
-
statusCode: 400
|
|
41
|
-
})
|
|
37
|
+
code: 'invalid_code',
|
|
38
|
+
message: 'This code is invalid',
|
|
39
|
+
human: 'Deze code is ongeldig of vervallen.',
|
|
40
|
+
statusCode: 400,
|
|
41
|
+
});
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
const user = await User.getByID(code.userId)
|
|
44
|
+
const user = await User.getByID(code.userId);
|
|
45
45
|
|
|
46
46
|
if (!user || (user.organizationId !== null && user.organizationId !== (organization?.id ?? null))) {
|
|
47
47
|
throw new SimpleError({
|
|
48
|
-
code:
|
|
49
|
-
message:
|
|
50
|
-
human:
|
|
51
|
-
statusCode: 400
|
|
52
|
-
})
|
|
48
|
+
code: 'invalid_code',
|
|
49
|
+
message: 'This code is invalid',
|
|
50
|
+
human: 'Deze code is ongeldig of vervallen.',
|
|
51
|
+
statusCode: 400,
|
|
52
|
+
});
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
if (user.email
|
|
56
|
-
const other = await User.getForAuthentication(user.organizationId, code.email, {allowWithoutAccount: true})
|
|
55
|
+
if (user.email !== code.email) {
|
|
56
|
+
const other = await User.getForAuthentication(user.organizationId, code.email, { allowWithoutAccount: true });
|
|
57
57
|
|
|
58
58
|
if (other) {
|
|
59
59
|
// Delete the other user, but merge data
|
|
60
60
|
await user.merge(other);
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
// change user email
|
|
64
|
-
user.email = code.email
|
|
64
|
+
user.email = code.email;
|
|
65
65
|
|
|
66
66
|
// If already in use: will fail, so will verification
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
user.verified = true
|
|
69
|
+
user.verified = true;
|
|
70
70
|
|
|
71
71
|
try {
|
|
72
|
-
await user.save()
|
|
73
|
-
}
|
|
72
|
+
await user.save();
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
74
75
|
// Duplicate key probably
|
|
75
|
-
if (e.code && e.code ==
|
|
76
|
+
if (e.code && e.code == 'ER_DUP_ENTRY') {
|
|
76
77
|
throw new SimpleError({
|
|
77
|
-
code:
|
|
78
|
-
message:
|
|
79
|
-
human:
|
|
80
|
-
})
|
|
78
|
+
code: 'email_in_use',
|
|
79
|
+
message: 'This e-mail is already in use, we cannot set it',
|
|
80
|
+
human: 'We kunnen het e-mailadres van deze gebruiker niet instellen naar ' + code.email + ', omdat die al in gebruik is. Waarschijnlijk heb je meerdere accounts. Probeer met dat e-mailadres in te loggen of contacteer ons (' + request.$t('59b85264-c4c3-4cf6-8923-9b43282b2787') + ') als we de gebruikers moeten combineren tot één gebruiker.',
|
|
81
|
+
});
|
|
81
82
|
}
|
|
82
83
|
throw e;
|
|
83
84
|
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { AutoEncoder, Decoder, field, StringDecoder } from '@simonbackx/simple-encoding';
|
|
2
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
2
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { City } from '@stamhoofd/models';
|
|
4
4
|
import { Province } from '@stamhoofd/models';
|
|
5
|
-
import { City as CityStruct, Country, Province as ProvinceStruct,SearchRegions } from
|
|
5
|
+
import { City as CityStruct, Country, Province as ProvinceStruct, SearchRegions } from '@stamhoofd/structures';
|
|
6
6
|
import { StringCompare } from '@stamhoofd/utility';
|
|
7
7
|
|
|
8
8
|
type Params = Record<string, never>;
|
|
9
9
|
class Query extends AutoEncoder {
|
|
10
10
|
@field({ decoder: StringDecoder })
|
|
11
|
-
query: string
|
|
11
|
+
query: string;
|
|
12
12
|
}
|
|
13
13
|
type Body = undefined;
|
|
14
14
|
type ResponseBody = SearchRegions;
|
|
15
15
|
|
|
16
16
|
export class SearchRegionsEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
17
|
-
queryDecoder = Query as Decoder<Query
|
|
18
|
-
|
|
17
|
+
queryDecoder = Query as Decoder<Query>;
|
|
18
|
+
|
|
19
19
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
20
|
-
if (request.method
|
|
20
|
+
if (request.method !== 'GET') {
|
|
21
21
|
return [false];
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const params = Endpoint.parseParameters(request.url,
|
|
24
|
+
const params = Endpoint.parseParameters(request.url, '/address/search', {});
|
|
25
25
|
|
|
26
26
|
if (params) {
|
|
27
27
|
return [true, params as Params];
|
|
@@ -30,8 +30,8 @@ export class SearchRegionsEndpoint extends Endpoint<Params, Query, Body, Respons
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
33
|
-
|
|
34
|
-
const query = request.query.query.replace(/([-+><()~*"@\s]+)/g,
|
|
33
|
+
// Escape query
|
|
34
|
+
const query = request.query.query.replace(/([-+><()~*"@\s]+)/g, ' ').replace(/[^\w\d]+$/, '');
|
|
35
35
|
if (query.length == 0) {
|
|
36
36
|
// Do not try searching...
|
|
37
37
|
return new Response(SearchRegions.create({
|
|
@@ -42,9 +42,9 @@ export class SearchRegionsEndpoint extends Endpoint<Params, Query, Body, Respons
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
const match = {
|
|
45
|
-
sign:
|
|
46
|
-
value: query +
|
|
47
|
-
mode:
|
|
45
|
+
sign: 'MATCH',
|
|
46
|
+
value: query + '*', // We replace special operators in boolean mode with spaces since special characters aren't indexed anyway
|
|
47
|
+
mode: 'BOOLEAN',
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
// We had to add an order by in the query to fix the limit. MySQL doesn't want to limit the results correctly if we don't explicitly sort the results on their relevance
|
|
@@ -53,11 +53,11 @@ export class SearchRegionsEndpoint extends Endpoint<Params, Query, Body, Respons
|
|
|
53
53
|
sort: [
|
|
54
54
|
{
|
|
55
55
|
column: { name: match },
|
|
56
|
-
direction:
|
|
57
|
-
}
|
|
58
|
-
]
|
|
56
|
+
direction: 'DESC',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
59
|
});
|
|
60
|
-
const loadedCities: (City & { province: Province })[] = []
|
|
60
|
+
const loadedCities: (City & { province: Province })[] = [];
|
|
61
61
|
|
|
62
62
|
// We had to add an order by in the query to fix the limit. MySQL doesn't want to limit the results correctly if we don't explicitly sort the results on their relevance
|
|
63
63
|
const allProvinces = await Province.all();
|
|
@@ -67,41 +67,41 @@ export class SearchRegionsEndpoint extends Endpoint<Params, Query, Body, Respons
|
|
|
67
67
|
if (!province) {
|
|
68
68
|
continue;
|
|
69
69
|
}
|
|
70
|
-
loadedCities.push(city.setRelation(City.province, province))
|
|
70
|
+
loadedCities.push(city.setRelation(City.province, province));
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
const provinces: Province[] = []
|
|
73
|
+
const provinces: Province[] = [];
|
|
74
74
|
for (const province of allProvinces) {
|
|
75
75
|
if (StringCompare.typoCount(request.query.query, province.name) < 3) {
|
|
76
|
-
provinces.push(province)
|
|
76
|
+
provinces.push(province);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
const countries: Country[] = []
|
|
81
|
-
if (StringCompare.typoCount(request.query.query,
|
|
82
|
-
countries.push(Country.Belgium)
|
|
80
|
+
const countries: Country[] = [];
|
|
81
|
+
if (StringCompare.typoCount(request.query.query, 'België') < 3) {
|
|
82
|
+
countries.push(Country.Belgium);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
if (StringCompare.typoCount(request.query.query,
|
|
86
|
-
countries.push(Country.Netherlands)
|
|
85
|
+
if (StringCompare.typoCount(request.query.query, 'Nederland') < 3) {
|
|
86
|
+
countries.push(Country.Netherlands);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
if (StringCompare.typoCount(request.query.query,
|
|
90
|
-
countries.push(Country.Luxembourg)
|
|
89
|
+
if (StringCompare.typoCount(request.query.query, 'Luxemburg') < 3) {
|
|
90
|
+
countries.push(Country.Luxembourg);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
if (StringCompare.typoCount(request.query.query,
|
|
94
|
-
countries.push(Country.Germany)
|
|
93
|
+
if (StringCompare.typoCount(request.query.query, 'Duitsland') < 3) {
|
|
94
|
+
countries.push(Country.Germany);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
if (StringCompare.typoCount(request.query.query,
|
|
98
|
-
countries.push(Country.France)
|
|
97
|
+
if (StringCompare.typoCount(request.query.query, 'Frankrijk') < 3) {
|
|
98
|
+
countries.push(Country.France);
|
|
99
99
|
}
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
return new Response(SearchRegions.create({
|
|
102
|
-
cities: loadedCities.map(c => CityStruct.create(Object.assign({...c}, { province: ProvinceStruct.create(c.province) }))),
|
|
102
|
+
cities: loadedCities.map(c => CityStruct.create(Object.assign({ ...c }, { province: ProvinceStruct.create(c.province) }))),
|
|
103
103
|
provinces: provinces.map(c => ProvinceStruct.create(c)),
|
|
104
|
-
countries: countries
|
|
104
|
+
countries: countries,
|
|
105
105
|
}));
|
|
106
106
|
}
|
|
107
107
|
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { Decoder } from '@simonbackx/simple-encoding';
|
|
2
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
3
|
-
import { Address, ValidatedAddress } from
|
|
2
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
|
+
import { Address, ValidatedAddress } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
5
|
import { AddressValidator } from '../../../helpers/AddressValidator';
|
|
6
6
|
|
|
7
7
|
type Params = Record<string, never>;
|
|
8
8
|
type Query = undefined;
|
|
9
|
-
type Body = Address
|
|
9
|
+
type Body = Address;
|
|
10
10
|
type ResponseBody = ValidatedAddress;
|
|
11
11
|
|
|
12
12
|
export class ValidateAddressEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
13
|
-
bodyDecoder = Address as Decoder<Address
|
|
14
|
-
|
|
13
|
+
bodyDecoder = Address as Decoder<Address>;
|
|
14
|
+
|
|
15
15
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
16
|
-
if (request.method
|
|
16
|
+
if (request.method !== 'POST') {
|
|
17
17
|
return [false];
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
const params = Endpoint.parseParameters(request.url,
|
|
20
|
+
const params = Endpoint.parseParameters(request.url, '/address/validate', {});
|
|
21
21
|
|
|
22
22
|
if (params) {
|
|
23
23
|
return [true, params as Params];
|
|
@@ -1,5 +1,5 @@
|
|
|
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, Webshop } from '@stamhoofd/models';
|
|
5
5
|
type Params = Record<string, never>;
|
|
@@ -9,20 +9,20 @@ class Query extends AutoEncoder {
|
|
|
9
9
|
domain: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
type Body = undefined
|
|
12
|
+
type Body = undefined;
|
|
13
13
|
type ResponseBody = undefined;
|
|
14
14
|
|
|
15
15
|
export class CheckDomainCertEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
16
16
|
queryDecoder = Query as Decoder<Query>;
|
|
17
17
|
|
|
18
|
-
registrationDomains = [...
|
|
18
|
+
registrationDomains = [...new Set(Object.values(STAMHOOFD.domains.registration ?? {}))];
|
|
19
19
|
|
|
20
20
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
21
|
-
if (request.method
|
|
21
|
+
if (request.method !== 'GET') {
|
|
22
22
|
return [false];
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
const params = Endpoint.parseParameters(request.url,
|
|
25
|
+
const params = Endpoint.parseParameters(request.url, '/check-domain-cert', {});
|
|
26
26
|
|
|
27
27
|
if (params) {
|
|
28
28
|
return [true, params as Params];
|
|
@@ -33,69 +33,69 @@ export class CheckDomainCertEndpoint extends Endpoint<Params, Query, Body, Respo
|
|
|
33
33
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
34
34
|
// check if the domain ends on one of our localized registration domains
|
|
35
35
|
for (const domain of this.registrationDomains) {
|
|
36
|
-
if (request.query.domain.endsWith(
|
|
37
|
-
const strippped = request.query.domain.substr(0, request.query.domain.length - (
|
|
38
|
-
if (strippped.includes(
|
|
36
|
+
if (request.query.domain.endsWith('.' + domain)) {
|
|
37
|
+
const strippped = request.query.domain.substr(0, request.query.domain.length - ('.' + domain).length);
|
|
38
|
+
if (strippped.includes('.')) {
|
|
39
39
|
throw new SimpleError({
|
|
40
|
-
code:
|
|
41
|
-
message:
|
|
42
|
-
statusCode: 404
|
|
43
|
-
})
|
|
40
|
+
code: 'invalid_domain',
|
|
41
|
+
message: 'This domain format is not supported',
|
|
42
|
+
statusCode: 404,
|
|
43
|
+
});
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// Search for the URI
|
|
47
|
-
const organization = await Organization.getByURI(strippped)
|
|
47
|
+
const organization = await Organization.getByURI(strippped);
|
|
48
48
|
|
|
49
49
|
if (!organization) {
|
|
50
50
|
throw new SimpleError({
|
|
51
|
-
code:
|
|
52
|
-
message:
|
|
53
|
-
statusCode: 404
|
|
54
|
-
})
|
|
51
|
+
code: 'unknown_domain',
|
|
52
|
+
message: 'Not known',
|
|
53
|
+
statusCode: 404,
|
|
54
|
+
});
|
|
55
55
|
}
|
|
56
56
|
return new Response(undefined);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
if (STAMHOOFD.domains.legacyWebshop && request.query.domain.endsWith(
|
|
61
|
-
const strippped = request.query.domain.substr(0, request.query.domain.length - (
|
|
62
|
-
if (strippped.includes(
|
|
59
|
+
|
|
60
|
+
if (STAMHOOFD.domains.legacyWebshop && request.query.domain.endsWith('.' + STAMHOOFD.domains.legacyWebshop)) {
|
|
61
|
+
const strippped = request.query.domain.substr(0, request.query.domain.length - ('.' + STAMHOOFD.domains.legacyWebshop).length);
|
|
62
|
+
if (strippped.includes('.')) {
|
|
63
63
|
throw new SimpleError({
|
|
64
|
-
code:
|
|
65
|
-
message:
|
|
66
|
-
statusCode: 404
|
|
67
|
-
})
|
|
64
|
+
code: 'invalid_domain',
|
|
65
|
+
message: 'This domain format is not supported',
|
|
66
|
+
statusCode: 404,
|
|
67
|
+
});
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// Search for the URI
|
|
71
|
-
const organization = await Organization.getByURI(strippped)
|
|
71
|
+
const organization = await Organization.getByURI(strippped);
|
|
72
72
|
|
|
73
73
|
if (!organization) {
|
|
74
74
|
throw new SimpleError({
|
|
75
|
-
code:
|
|
76
|
-
message:
|
|
77
|
-
statusCode: 404
|
|
78
|
-
})
|
|
75
|
+
code: 'unknown_domain',
|
|
76
|
+
message: 'Not known',
|
|
77
|
+
statusCode: 404,
|
|
78
|
+
});
|
|
79
79
|
}
|
|
80
80
|
return new Response(undefined);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// Check if we have an organization with a custom domain name
|
|
84
|
-
const organization = await Organization.getByRegisterDomain(request.query.domain)
|
|
84
|
+
const organization = await Organization.getByRegisterDomain(request.query.domain);
|
|
85
85
|
|
|
86
86
|
if (organization) {
|
|
87
87
|
return new Response(undefined);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
const webshops = await Webshop.getByDomainOnly(request.query.domain)
|
|
90
|
+
const webshops = await Webshop.getByDomainOnly(request.query.domain);
|
|
91
91
|
if (webshops.length > 0) {
|
|
92
92
|
return new Response(undefined);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
throw new SimpleError({
|
|
96
|
-
code:
|
|
97
|
-
message:
|
|
98
|
-
statusCode: 404
|
|
99
|
-
})
|
|
96
|
+
code: 'unknown_domain',
|
|
97
|
+
message: 'Not known',
|
|
98
|
+
statusCode: 404,
|
|
99
|
+
});
|
|
100
100
|
}
|
|
101
101
|
}
|
|
@@ -1,44 +1,44 @@
|
|
|
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 { Email, EmailTemplate, RateLimiter } from '@stamhoofd/models';
|
|
4
|
-
import { EmailPreview, EmailStatus, Email as EmailStruct, Version, EmailTemplate as EmailTemplateStruct } from
|
|
4
|
+
import { EmailPreview, EmailStatus, Email as EmailStruct, Version, EmailTemplate as EmailTemplateStruct } from '@stamhoofd/structures';
|
|
5
5
|
|
|
6
6
|
import { Context } from '../../../helpers/Context';
|
|
7
7
|
import { SQL } from '@stamhoofd/sql';
|
|
8
8
|
|
|
9
9
|
type Params = Record<string, never>;
|
|
10
10
|
type Query = undefined;
|
|
11
|
-
type Body = EmailStruct
|
|
11
|
+
type Body = EmailStruct;
|
|
12
12
|
type ResponseBody = EmailPreview;
|
|
13
13
|
|
|
14
14
|
export const paidEmailRateLimiter = new RateLimiter({
|
|
15
15
|
limits: [
|
|
16
|
-
{
|
|
16
|
+
{
|
|
17
17
|
// Max 5.000 emails a day
|
|
18
18
|
limit: 5000,
|
|
19
|
-
duration: 24 * 60 * 1000 * 60
|
|
19
|
+
duration: 24 * 60 * 1000 * 60,
|
|
20
20
|
},
|
|
21
|
-
{
|
|
21
|
+
{
|
|
22
22
|
// 10.000 requests per week
|
|
23
23
|
limit: 10000,
|
|
24
|
-
duration: 24 * 60 * 1000 * 60 * 7
|
|
25
|
-
}
|
|
26
|
-
]
|
|
24
|
+
duration: 24 * 60 * 1000 * 60 * 7,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
export const freeEmailRateLimiter = new RateLimiter({
|
|
30
30
|
limits: [
|
|
31
|
-
{
|
|
31
|
+
{
|
|
32
32
|
// Max 100 a day
|
|
33
33
|
limit: 100,
|
|
34
|
-
duration: 24 * 60 * 1000 * 60
|
|
34
|
+
duration: 24 * 60 * 1000 * 60,
|
|
35
35
|
},
|
|
36
|
-
{
|
|
36
|
+
{
|
|
37
37
|
// Max 200 a week
|
|
38
38
|
limit: 200,
|
|
39
|
-
duration: 7 * 24 * 60 * 1000 * 60
|
|
40
|
-
}
|
|
41
|
-
]
|
|
39
|
+
duration: 7 * 24 * 60 * 1000 * 60,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -46,14 +46,14 @@ export const freeEmailRateLimiter = new RateLimiter({
|
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
48
|
export class CreateEmailEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
49
|
-
bodyDecoder = EmailStruct as Decoder<EmailStruct
|
|
49
|
+
bodyDecoder = EmailStruct as Decoder<EmailStruct>;
|
|
50
50
|
|
|
51
51
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
52
|
-
if (request.method
|
|
52
|
+
if (request.method !== 'POST') {
|
|
53
53
|
return [false];
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
const params = Endpoint.parseParameters(request.url,
|
|
56
|
+
const params = Endpoint.parseParameters(request.url, '/email', {});
|
|
57
57
|
|
|
58
58
|
if (params) {
|
|
59
59
|
return [true, params as Params];
|
|
@@ -63,10 +63,10 @@ export class CreateEmailEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
63
63
|
|
|
64
64
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
65
65
|
const organization = await Context.setOptionalOrganizationScope();
|
|
66
|
-
const {user} = await Context.authenticate()
|
|
66
|
+
const { user } = await Context.authenticate();
|
|
67
67
|
|
|
68
68
|
if (!Context.auth.canSendEmails()) {
|
|
69
|
-
throw Context.auth.error()
|
|
69
|
+
throw Context.auth.error();
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const model = new Email();
|
|
@@ -83,24 +83,25 @@ export class CreateEmailEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
83
83
|
model.fromAddress = request.body.fromAddress;
|
|
84
84
|
model.fromName = request.body.fromName;
|
|
85
85
|
|
|
86
|
-
model.validateAttachments()
|
|
86
|
+
model.validateAttachments();
|
|
87
87
|
|
|
88
88
|
// Check default
|
|
89
89
|
if (JSON.stringify(model.json).length < 3 && model.recipientFilter.filters[0].type && EmailTemplateStruct.getDefaultForRecipient(model.recipientFilter.filters[0].type)) {
|
|
90
|
-
const type = EmailTemplateStruct.getDefaultForRecipient(model.recipientFilter.filters[0].type)
|
|
91
|
-
|
|
90
|
+
const type = EmailTemplateStruct.getDefaultForRecipient(model.recipientFilter.filters[0].type);
|
|
91
|
+
|
|
92
92
|
// Most specific template: for specific group
|
|
93
|
-
let templates = (await EmailTemplate.where({ type, organizationId: organization?.id ?? null, groupId: null }))
|
|
93
|
+
let templates = (await EmailTemplate.where({ type, organizationId: organization?.id ?? null, groupId: null }));
|
|
94
94
|
|
|
95
95
|
// Then default
|
|
96
96
|
if (templates.length == 0 && organization) {
|
|
97
|
-
templates = (await EmailTemplate.where({ type, organizationId: null, groupId: null }))
|
|
97
|
+
templates = (await EmailTemplate.where({ type, organizationId: null, groupId: null }));
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
if (templates.length == 0) {
|
|
101
101
|
// No default
|
|
102
|
-
}
|
|
103
|
-
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const defaultTemplate = templates[0];
|
|
104
105
|
model.html = defaultTemplate.html;
|
|
105
106
|
model.text = defaultTemplate.text;
|
|
106
107
|
model.subject = defaultTemplate.subject;
|
|
@@ -109,14 +110,13 @@ export class CreateEmailEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
await model.save();
|
|
112
|
-
await model.buildExampleRecipient()
|
|
113
|
+
await model.buildExampleRecipient();
|
|
113
114
|
model.updateCount();
|
|
114
115
|
|
|
115
116
|
if (request.body.status === EmailStatus.Sending || request.body.status === EmailStatus.Sent) {
|
|
116
|
-
model.send().catch(console.error)
|
|
117
|
+
model.send().catch(console.error);
|
|
117
118
|
}
|
|
118
119
|
|
|
119
|
-
|
|
120
120
|
return new Response(await model.getPreviewStructure());
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AutoEncoder, Decoder, field, StringDecoder } 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 { EmailAddress } from '@stamhoofd/email';
|
|
5
5
|
import { Organization } from '@stamhoofd/models';
|
|
@@ -10,10 +10,10 @@ type Body = undefined;
|
|
|
10
10
|
|
|
11
11
|
class Query extends AutoEncoder {
|
|
12
12
|
@field({ decoder: StringDecoder })
|
|
13
|
-
id: string
|
|
13
|
+
id: string;
|
|
14
14
|
|
|
15
15
|
@field({ decoder: StringDecoder })
|
|
16
|
-
token: string
|
|
16
|
+
token: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
type ResponseBody = EmailAddressSettings;
|
|
@@ -22,11 +22,11 @@ export class ManageEmailAddressEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
22
22
|
queryDecoder = Query as Decoder<Query>;
|
|
23
23
|
|
|
24
24
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
25
|
-
if (request.method
|
|
25
|
+
if (request.method !== 'GET') {
|
|
26
26
|
return [false];
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const params = Endpoint.parseParameters(request.url,
|
|
29
|
+
const params = Endpoint.parseParameters(request.url, '/email/manage', {});
|
|
30
30
|
|
|
31
31
|
if (params) {
|
|
32
32
|
return [true, params as Params];
|
|
@@ -35,19 +35,19 @@ export class ManageEmailAddressEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
38
|
-
const email = await EmailAddress.getByID(request.query.id)
|
|
38
|
+
const email = await EmailAddress.getByID(request.query.id);
|
|
39
39
|
if (!email || email.token !== request.query.token || request.query.token.length < 10 || request.query.id.length < 10) {
|
|
40
40
|
throw new SimpleError({
|
|
41
|
-
code:
|
|
42
|
-
message:
|
|
43
|
-
human:
|
|
44
|
-
})
|
|
41
|
+
code: 'invalid_fields',
|
|
42
|
+
message: 'Invalid token or id',
|
|
43
|
+
human: 'Deze link is vervallen. Probeer het opnieuw in een recentere e-mail',
|
|
44
|
+
});
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
const organization = email.organizationId ? (await Organization.getByID(email.organizationId)) : undefined
|
|
47
|
+
const organization = email.organizationId ? (await Organization.getByID(email.organizationId)) : undefined;
|
|
48
48
|
return new Response(EmailAddressSettings.create({
|
|
49
49
|
...email,
|
|
50
|
-
organization: organization ? OrganizationSimple.create(organization) : null
|
|
50
|
+
organization: organization ? OrganizationSimple.create(organization) : null,
|
|
51
51
|
}));
|
|
52
52
|
}
|
|
53
|
-
}
|
|
53
|
+
}
|