@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
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
1
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { Email } from '@stamhoofd/models';
|
|
3
|
-
import { EmailPreview } from
|
|
3
|
+
import { EmailPreview } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
5
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
6
6
|
import { Context } from '../../../helpers/Context';
|
|
7
7
|
|
|
8
|
-
type Params = {id: string};
|
|
8
|
+
type Params = { id: string };
|
|
9
9
|
type Query = undefined;
|
|
10
|
-
type Body = undefined
|
|
10
|
+
type Body = undefined;
|
|
11
11
|
type ResponseBody = EmailPreview;
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -16,11 +16,11 @@ type ResponseBody = EmailPreview;
|
|
|
16
16
|
|
|
17
17
|
export class GetEmailEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
18
18
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
19
|
-
if (request.method
|
|
19
|
+
if (request.method !== 'GET') {
|
|
20
20
|
return [false];
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const params = Endpoint.parseParameters(request.url,
|
|
23
|
+
const params = Endpoint.parseParameters(request.url, '/email/@id', { id: String });
|
|
24
24
|
|
|
25
25
|
if (params) {
|
|
26
26
|
return [true, params as Params];
|
|
@@ -30,20 +30,20 @@ export class GetEmailEndpoint extends Endpoint<Params, Query, Body, ResponseBody
|
|
|
30
30
|
|
|
31
31
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
32
32
|
const organization = await Context.setOptionalOrganizationScope();
|
|
33
|
-
const {user} = await Context.authenticate()
|
|
33
|
+
const { user } = await Context.authenticate();
|
|
34
34
|
|
|
35
35
|
if (!Context.auth.canSendEmails()) {
|
|
36
|
-
throw Context.auth.error()
|
|
37
|
-
}
|
|
36
|
+
throw Context.auth.error();
|
|
37
|
+
}
|
|
38
38
|
|
|
39
39
|
const model = await Email.getByID(request.params.id);
|
|
40
40
|
if (!model || model.userId !== user.id || (model.organizationId !== (organization?.id ?? null))) {
|
|
41
41
|
throw new SimpleError({
|
|
42
|
-
code:
|
|
43
|
-
human:
|
|
42
|
+
code: 'not_found',
|
|
43
|
+
human: 'Email not found',
|
|
44
44
|
message: 'Deze e-mail bestaat niet of is verwijderd',
|
|
45
|
-
statusCode: 404
|
|
46
|
-
})
|
|
45
|
+
statusCode: 404,
|
|
46
|
+
});
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
return new Response(await model.getPreviewStructure());
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AutoEncoder, BooleanDecoder, 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
|
|
|
@@ -8,16 +8,16 @@ type Query = undefined;
|
|
|
8
8
|
|
|
9
9
|
class Body extends AutoEncoder {
|
|
10
10
|
@field({ decoder: StringDecoder })
|
|
11
|
-
id: string
|
|
11
|
+
id: string;
|
|
12
12
|
|
|
13
13
|
@field({ decoder: StringDecoder })
|
|
14
|
-
token: string
|
|
14
|
+
token: string;
|
|
15
15
|
|
|
16
16
|
@field({ decoder: BooleanDecoder, optional: true })
|
|
17
|
-
unsubscribedMarketing?: boolean
|
|
17
|
+
unsubscribedMarketing?: boolean;
|
|
18
18
|
|
|
19
19
|
@field({ decoder: BooleanDecoder, optional: true })
|
|
20
|
-
unsubscribedAll?: boolean
|
|
20
|
+
unsubscribedAll?: boolean;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
type ResponseBody = undefined;
|
|
@@ -26,11 +26,11 @@ export class ManageEmailAddressEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
26
26
|
bodyDecoder = Body as Decoder<Body>;
|
|
27
27
|
|
|
28
28
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
29
|
-
if (request.method
|
|
29
|
+
if (request.method !== 'POST') {
|
|
30
30
|
return [false];
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
const params = Endpoint.parseParameters(request.url,
|
|
33
|
+
const params = Endpoint.parseParameters(request.url, '/email/manage', {});
|
|
34
34
|
|
|
35
35
|
if (params) {
|
|
36
36
|
return [true, params as Params];
|
|
@@ -39,19 +39,19 @@ export class ManageEmailAddressEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
42
|
-
const email = await EmailAddress.getByID(request.body.id)
|
|
42
|
+
const email = await EmailAddress.getByID(request.body.id);
|
|
43
43
|
if (!email || email.token !== request.body.token || request.body.token.length < 10 || request.body.id.length < 10) {
|
|
44
44
|
throw new SimpleError({
|
|
45
|
-
code:
|
|
46
|
-
message:
|
|
47
|
-
human:
|
|
48
|
-
})
|
|
45
|
+
code: 'invalid_fields',
|
|
46
|
+
message: 'Invalid token or id',
|
|
47
|
+
human: 'Deze link is vervallen. Probeer het opnieuw in een recentere e-mail',
|
|
48
|
+
});
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
email.unsubscribedAll = request.body.unsubscribedAll ?? email.unsubscribedAll
|
|
52
|
-
email.unsubscribedMarketing = request.body.unsubscribedMarketing ?? email.unsubscribedMarketing
|
|
51
|
+
email.unsubscribedAll = request.body.unsubscribedAll ?? email.unsubscribedAll;
|
|
52
|
+
email.unsubscribedMarketing = request.body.unsubscribedMarketing ?? email.unsubscribedMarketing;
|
|
53
53
|
|
|
54
|
-
await email.save()
|
|
54
|
+
await email.save();
|
|
55
55
|
return new Response(undefined);
|
|
56
56
|
}
|
|
57
|
-
}
|
|
57
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
1
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { Email } from '@stamhoofd/models';
|
|
3
|
-
import { EmailPreview, EmailStatus, Email as EmailStruct } from
|
|
3
|
+
import { EmailPreview, EmailStatus, Email as EmailStruct } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
5
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
6
6
|
import { Context } from '../../../helpers/Context';
|
|
7
|
-
import { AutoEncoderPatchType, Decoder, patchObject } from
|
|
7
|
+
import { AutoEncoderPatchType, Decoder, patchObject } from '@simonbackx/simple-encoding';
|
|
8
8
|
|
|
9
|
-
type Params = {id: string};
|
|
9
|
+
type Params = { id: string };
|
|
10
10
|
type Query = undefined;
|
|
11
|
-
type Body = AutoEncoderPatchType<EmailStruct
|
|
11
|
+
type Body = AutoEncoderPatchType<EmailStruct>;
|
|
12
12
|
type ResponseBody = EmailPreview;
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -16,14 +16,14 @@ type ResponseBody = EmailPreview;
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
export class PatchEmailEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
19
|
-
bodyDecoder = EmailStruct.patchType() as Decoder<AutoEncoderPatchType<EmailStruct
|
|
19
|
+
bodyDecoder = EmailStruct.patchType() as Decoder<AutoEncoderPatchType<EmailStruct>>;
|
|
20
20
|
|
|
21
21
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
22
|
-
if (request.method
|
|
22
|
+
if (request.method !== 'PATCH') {
|
|
23
23
|
return [false];
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const params = Endpoint.parseParameters(request.url,
|
|
26
|
+
const params = Endpoint.parseParameters(request.url, '/email/@id', { id: String });
|
|
27
27
|
|
|
28
28
|
if (params) {
|
|
29
29
|
return [true, params as Params];
|
|
@@ -33,29 +33,29 @@ export class PatchEmailEndpoint extends Endpoint<Params, Query, Body, ResponseBo
|
|
|
33
33
|
|
|
34
34
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
35
35
|
const organization = await Context.setOptionalOrganizationScope();
|
|
36
|
-
const {user} = await Context.authenticate()
|
|
36
|
+
const { user } = await Context.authenticate();
|
|
37
37
|
|
|
38
38
|
if (!Context.auth.canSendEmails()) {
|
|
39
|
-
throw Context.auth.error()
|
|
40
|
-
}
|
|
39
|
+
throw Context.auth.error();
|
|
40
|
+
}
|
|
41
41
|
|
|
42
42
|
const model = await Email.getByID(request.params.id);
|
|
43
43
|
if (!model || model.userId !== user.id || (model.organizationId !== (organization?.id ?? null))) {
|
|
44
44
|
throw new SimpleError({
|
|
45
|
-
code:
|
|
46
|
-
human:
|
|
45
|
+
code: 'not_found',
|
|
46
|
+
human: 'Email not found',
|
|
47
47
|
message: 'Deze e-mail bestaat niet of is verwijderd',
|
|
48
|
-
statusCode: 404
|
|
49
|
-
})
|
|
48
|
+
statusCode: 404,
|
|
49
|
+
});
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
if (model.status !== EmailStatus.Draft) {
|
|
53
53
|
throw new SimpleError({
|
|
54
|
-
code:
|
|
55
|
-
human:
|
|
54
|
+
code: 'not_draft',
|
|
55
|
+
human: 'Email is not a draft',
|
|
56
56
|
message: 'Deze e-mail is al verzonden en kan niet meer aangepast worden',
|
|
57
|
-
statusCode: 400
|
|
58
|
-
})
|
|
57
|
+
statusCode: 400,
|
|
58
|
+
});
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
let rebuild = false;
|
|
@@ -92,22 +92,22 @@ export class PatchEmailEndpoint extends Endpoint<Params, Query, Body, ResponseBo
|
|
|
92
92
|
// Attachments
|
|
93
93
|
if (request.body.attachments !== undefined) {
|
|
94
94
|
model.attachments = patchObject(model.attachments, request.body.attachments);
|
|
95
|
-
model.validateAttachments()
|
|
95
|
+
model.validateAttachments();
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
await model.save();
|
|
99
99
|
|
|
100
100
|
if (rebuild) {
|
|
101
|
-
await model.buildExampleRecipient()
|
|
102
|
-
model.updateCount()
|
|
101
|
+
await model.buildExampleRecipient();
|
|
102
|
+
model.updateCount();
|
|
103
103
|
|
|
104
104
|
// Force null - because we have stale data
|
|
105
|
-
model.recipientCount = null
|
|
105
|
+
model.recipientCount = null;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
if (request.body.status === EmailStatus.Sending || request.body.status === EmailStatus.Sent) {
|
|
109
|
-
model.throwIfNotReadyToSend()
|
|
110
|
-
model.send().catch(console.error)
|
|
109
|
+
model.throwIfNotReadyToSend();
|
|
110
|
+
model.send().catch(console.error);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
return new Response(await model.getPreviewStructure());
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
2
1
|
import { Decoder } from '@simonbackx/simple-encoding';
|
|
3
2
|
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
4
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
5
4
|
import { Event } from '@stamhoofd/models';
|
|
6
|
-
import { SQL, SQLFilterDefinitions, SQLSortDefinitions, compileToSQLFilter, compileToSQLSorter } from
|
|
5
|
+
import { SQL, SQLFilterDefinitions, SQLSortDefinitions, compileToSQLFilter, compileToSQLSorter } from '@stamhoofd/sql';
|
|
7
6
|
import { CountFilteredRequest, Event as EventStruct, LimitedFilteredRequest, PaginatedResponse, StamhoofdFilter, assertSort, getSortFilter } from '@stamhoofd/structures';
|
|
8
7
|
|
|
9
8
|
import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
|
|
@@ -14,20 +13,20 @@ import { eventSorters } from '../../../sql-sorters/events';
|
|
|
14
13
|
type Params = Record<string, never>;
|
|
15
14
|
type Query = LimitedFilteredRequest;
|
|
16
15
|
type Body = undefined;
|
|
17
|
-
type ResponseBody = PaginatedResponse<EventStruct[], LimitedFilteredRequest
|
|
16
|
+
type ResponseBody = PaginatedResponse<EventStruct[], LimitedFilteredRequest>;
|
|
18
17
|
|
|
19
|
-
const filterCompilers: SQLFilterDefinitions = eventFilterCompilers
|
|
20
|
-
const sorters: SQLSortDefinitions<Event> = eventSorters
|
|
18
|
+
const filterCompilers: SQLFilterDefinitions = eventFilterCompilers;
|
|
19
|
+
const sorters: SQLSortDefinitions<Event> = eventSorters;
|
|
21
20
|
|
|
22
21
|
export class GetEventsEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
23
|
-
queryDecoder = LimitedFilteredRequest as Decoder<LimitedFilteredRequest
|
|
22
|
+
queryDecoder = LimitedFilteredRequest as Decoder<LimitedFilteredRequest>;
|
|
24
23
|
|
|
25
24
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
26
|
-
if (request.method
|
|
25
|
+
if (request.method !== 'GET') {
|
|
27
26
|
return [false];
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
const params = Endpoint.parseParameters(request.url,
|
|
29
|
+
const params = Endpoint.parseParameters(request.url, '/events', {});
|
|
31
30
|
|
|
32
31
|
if (params) {
|
|
33
32
|
return [true, params as Params];
|
|
@@ -35,74 +34,74 @@ export class GetEventsEndpoint extends Endpoint<Params, Query, Body, ResponseBod
|
|
|
35
34
|
return [false];
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
static buildQuery(q: CountFilteredRequest|LimitedFilteredRequest) {
|
|
39
|
-
const organization = Context.organization
|
|
40
|
-
let scopeFilter: StamhoofdFilter|undefined = undefined;
|
|
37
|
+
static buildQuery(q: CountFilteredRequest | LimitedFilteredRequest) {
|
|
38
|
+
const organization = Context.organization;
|
|
39
|
+
let scopeFilter: StamhoofdFilter | undefined = undefined;
|
|
41
40
|
|
|
42
41
|
if (organization) {
|
|
43
42
|
scopeFilter = {
|
|
44
43
|
$or: [
|
|
45
44
|
{
|
|
46
|
-
organizationId: organization.id
|
|
45
|
+
organizationId: organization.id,
|
|
47
46
|
},
|
|
48
47
|
{
|
|
49
|
-
organizationId: null
|
|
50
|
-
}
|
|
48
|
+
organizationId: null,
|
|
49
|
+
},
|
|
51
50
|
],
|
|
52
51
|
};
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
const query = SQL
|
|
56
55
|
.select(
|
|
57
|
-
SQL.wildcard(Event.table)
|
|
56
|
+
SQL.wildcard(Event.table),
|
|
58
57
|
)
|
|
59
58
|
.from(
|
|
60
|
-
SQL.table(Event.table)
|
|
59
|
+
SQL.table(Event.table),
|
|
61
60
|
);
|
|
62
|
-
|
|
61
|
+
|
|
63
62
|
if (scopeFilter) {
|
|
64
|
-
query.where(compileToSQLFilter(scopeFilter, filterCompilers))
|
|
63
|
+
query.where(compileToSQLFilter(scopeFilter, filterCompilers));
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
if (q.filter) {
|
|
68
|
-
query.where(compileToSQLFilter(q.filter, filterCompilers))
|
|
67
|
+
query.where(compileToSQLFilter(q.filter, filterCompilers));
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
if (q.search) {
|
|
72
|
-
let searchFilter: StamhoofdFilter|null = null
|
|
71
|
+
let searchFilter: StamhoofdFilter | null = null;
|
|
73
72
|
|
|
74
73
|
// todo: detect special search patterns and adjust search filter if needed
|
|
75
74
|
searchFilter = {
|
|
76
75
|
name: {
|
|
77
|
-
$contains: q.search
|
|
78
|
-
}
|
|
79
|
-
}
|
|
76
|
+
$contains: q.search,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
80
79
|
|
|
81
80
|
if (searchFilter) {
|
|
82
|
-
query.where(compileToSQLFilter(searchFilter, filterCompilers))
|
|
81
|
+
query.where(compileToSQLFilter(searchFilter, filterCompilers));
|
|
83
82
|
}
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
if (q instanceof LimitedFilteredRequest) {
|
|
87
86
|
if (q.pageFilter) {
|
|
88
|
-
query.where(compileToSQLFilter(q.pageFilter, filterCompilers))
|
|
87
|
+
query.where(compileToSQLFilter(q.pageFilter, filterCompilers));
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
q.sort = assertSort(q.sort, [{key: 'id'}])
|
|
92
|
-
query.orderBy(compileToSQLSorter(q.sort, sorters))
|
|
93
|
-
query.limit(q.limit)
|
|
90
|
+
q.sort = assertSort(q.sort, [{ key: 'id' }]);
|
|
91
|
+
query.orderBy(compileToSQLSorter(q.sort, sorters));
|
|
92
|
+
query.limit(q.limit);
|
|
94
93
|
}
|
|
95
|
-
|
|
96
|
-
return query
|
|
94
|
+
|
|
95
|
+
return query;
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
static async buildData(requestQuery: LimitedFilteredRequest) {
|
|
100
|
-
const query = GetEventsEndpoint.buildQuery(requestQuery)
|
|
101
|
-
const data = await query.fetch()
|
|
102
|
-
|
|
99
|
+
const query = GetEventsEndpoint.buildQuery(requestQuery);
|
|
100
|
+
const data = await query.fetch();
|
|
101
|
+
|
|
103
102
|
const events = Event.fromRows(data, Event.table);
|
|
104
103
|
|
|
105
|
-
let next: LimitedFilteredRequest|undefined;
|
|
104
|
+
let next: LimitedFilteredRequest | undefined;
|
|
106
105
|
|
|
107
106
|
if (events.length >= requestQuery.limit) {
|
|
108
107
|
const lastObject = events[events.length - 1];
|
|
@@ -113,8 +112,8 @@ export class GetEventsEndpoint extends Endpoint<Params, Query, Body, ResponseBod
|
|
|
113
112
|
pageFilter: nextFilter,
|
|
114
113
|
sort: requestQuery.sort,
|
|
115
114
|
limit: requestQuery.limit,
|
|
116
|
-
search: requestQuery.search
|
|
117
|
-
})
|
|
115
|
+
search: requestQuery.search,
|
|
116
|
+
});
|
|
118
117
|
|
|
119
118
|
if (JSON.stringify(nextFilter) === JSON.stringify(requestQuery.pageFilter)) {
|
|
120
119
|
console.error('Found infinite loading loop for', requestQuery);
|
|
@@ -124,13 +123,13 @@ export class GetEventsEndpoint extends Endpoint<Params, Query, Body, ResponseBod
|
|
|
124
123
|
|
|
125
124
|
return new PaginatedResponse<EventStruct[], LimitedFilteredRequest>({
|
|
126
125
|
results: await AuthenticatedStructures.events(events),
|
|
127
|
-
next
|
|
126
|
+
next,
|
|
128
127
|
});
|
|
129
128
|
}
|
|
130
129
|
|
|
131
130
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
132
131
|
await Context.setOptionalOrganizationScope();
|
|
133
|
-
await Context.authenticate()
|
|
132
|
+
await Context.authenticate();
|
|
134
133
|
|
|
135
134
|
const maxLimit = Context.auth.hasSomePlatformAccess() ? 1000 : 100;
|
|
136
135
|
|
|
@@ -138,20 +137,20 @@ export class GetEventsEndpoint extends Endpoint<Params, Query, Body, ResponseBod
|
|
|
138
137
|
throw new SimpleError({
|
|
139
138
|
code: 'invalid_field',
|
|
140
139
|
field: 'limit',
|
|
141
|
-
message: 'Limit can not be more than ' + maxLimit
|
|
142
|
-
})
|
|
140
|
+
message: 'Limit can not be more than ' + maxLimit,
|
|
141
|
+
});
|
|
143
142
|
}
|
|
144
143
|
|
|
145
144
|
if (request.query.limit < 1) {
|
|
146
145
|
throw new SimpleError({
|
|
147
146
|
code: 'invalid_field',
|
|
148
147
|
field: 'limit',
|
|
149
|
-
message: 'Limit can not be less than 1'
|
|
150
|
-
})
|
|
148
|
+
message: 'Limit can not be less than 1',
|
|
149
|
+
});
|
|
151
150
|
}
|
|
152
|
-
|
|
151
|
+
|
|
153
152
|
return new Response(
|
|
154
|
-
await GetEventsEndpoint.buildData(request.query)
|
|
153
|
+
await GetEventsEndpoint.buildData(request.query),
|
|
155
154
|
);
|
|
156
155
|
}
|
|
157
156
|
}
|