@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,28 +1,28 @@
|
|
|
1
|
-
import { Request } from
|
|
1
|
+
import { Request } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { OrganizationFactory } from '@stamhoofd/models';
|
|
3
3
|
import { OrganizationSimple } from '@stamhoofd/structures';
|
|
4
|
-
import { v4 as uuidv4 } from
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
5
5
|
|
|
6
6
|
import { testServer } from '../../../../tests/helpers/TestServer';
|
|
7
|
-
import { SearchOrganizationEndpoint } from
|
|
7
|
+
import { SearchOrganizationEndpoint } from './SearchOrganizationEndpoint';
|
|
8
8
|
|
|
9
|
-
describe(
|
|
9
|
+
describe('Endpoint.SearchOrganization', () => {
|
|
10
10
|
// Test endpoint
|
|
11
11
|
const endpoint = new SearchOrganizationEndpoint();
|
|
12
12
|
|
|
13
|
-
test(
|
|
13
|
+
test('Search for a given organization using exact search', async () => {
|
|
14
14
|
const organization = await new OrganizationFactory({
|
|
15
|
-
name: (uuidv4()).replace(/-/g,
|
|
16
|
-
}).create()
|
|
15
|
+
name: (uuidv4()).replace(/-/g, ''),
|
|
16
|
+
}).create();
|
|
17
17
|
|
|
18
|
-
const r = Request.buildJson(
|
|
18
|
+
const r = Request.buildJson('GET', '/v19/organizations/search');
|
|
19
19
|
r.query = {
|
|
20
|
-
query: organization.name
|
|
20
|
+
query: organization.name,
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
const response = await testServer.test(endpoint, r);
|
|
24
24
|
expect(response.body).toBeDefined();
|
|
25
|
-
expect(response.body).toHaveLength(1)
|
|
25
|
+
expect(response.body).toHaveLength(1);
|
|
26
26
|
|
|
27
27
|
// Access token should be expired
|
|
28
28
|
expect(response.body[0]).toBeInstanceOf(OrganizationSimple);
|
|
@@ -30,29 +30,29 @@ describe("Endpoint.SearchOrganization", () => {
|
|
|
30
30
|
expect(response.body[0]).toMatchObject({
|
|
31
31
|
id: organization.id,
|
|
32
32
|
name: organization.name,
|
|
33
|
-
address: organization.address
|
|
34
|
-
})
|
|
33
|
+
address: organization.address,
|
|
34
|
+
});
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
test(
|
|
38
|
-
const city = uuidv4()
|
|
37
|
+
test('Search for a given organization on city name using exact search', async () => {
|
|
38
|
+
const city = uuidv4();
|
|
39
39
|
const organizations = await new OrganizationFactory({
|
|
40
|
-
city
|
|
41
|
-
}).createMultiple(2)
|
|
40
|
+
city,
|
|
41
|
+
}).createMultiple(2);
|
|
42
42
|
|
|
43
|
-
const r = Request.buildJson(
|
|
43
|
+
const r = Request.buildJson('GET', '/v1/organizations/search');
|
|
44
44
|
r.query = {
|
|
45
|
-
query: city
|
|
45
|
+
query: city,
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
const response = await testServer.test(endpoint, r);
|
|
49
49
|
expect(response.body).toBeDefined();
|
|
50
|
-
expect(response.body).toHaveLength(2)
|
|
50
|
+
expect(response.body).toHaveLength(2);
|
|
51
51
|
|
|
52
52
|
// Access token should be expired
|
|
53
53
|
expect(response.body[0]).toBeInstanceOf(OrganizationSimple);
|
|
54
54
|
expect(response.body[1]).toBeInstanceOf(OrganizationSimple);
|
|
55
55
|
expect(response.status).toEqual(200);
|
|
56
|
-
expect(response.body.map(o => o.id).sort()).toEqual(organizations.map(o => o.id).sort())
|
|
56
|
+
expect(response.body.map(o => o.id).sort()).toEqual(organizations.map(o => o.id).sort());
|
|
57
57
|
});
|
|
58
58
|
});
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
import { AutoEncoder, Decoder, field, StringDecoder } from '@simonbackx/simple-encoding';
|
|
2
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
3
|
-
import { Organization } from
|
|
4
|
-
import { Organization as OrganizationStruct,OrganizationSimple } from
|
|
2
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
|
+
import { Organization } from '@stamhoofd/models';
|
|
4
|
+
import { Organization as OrganizationStruct, OrganizationSimple } from '@stamhoofd/structures';
|
|
5
5
|
import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
|
|
6
6
|
|
|
7
7
|
type Params = Record<string, never>;
|
|
8
8
|
|
|
9
9
|
class Query extends AutoEncoder {
|
|
10
10
|
@field({ decoder: StringDecoder })
|
|
11
|
-
query: string
|
|
11
|
+
query: string;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
type Body = undefined;
|
|
15
|
-
type ResponseBody = (OrganizationSimple | OrganizationStruct)[]
|
|
15
|
+
type ResponseBody = (OrganizationSimple | OrganizationStruct)[];
|
|
16
16
|
|
|
17
17
|
export class SearchOrganizationEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
18
|
-
protected queryDecoder = Query as Decoder<Query
|
|
18
|
+
protected queryDecoder = Query as Decoder<Query>;
|
|
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, '/organizations/search', {});
|
|
26
26
|
|
|
27
27
|
if (params) {
|
|
28
28
|
return [true, params as Params];
|
|
@@ -32,16 +32,16 @@ export class SearchOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
32
32
|
|
|
33
33
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
34
34
|
// Escape query
|
|
35
|
-
const query = request.query.query.replace(/([-+><()~*"@\s]+)/g,
|
|
35
|
+
const query = request.query.query.replace(/([-+><()~*"@\s]+)/g, ' ').replace(/[^\w\d]+$/, '');
|
|
36
36
|
if (query.length == 0) {
|
|
37
37
|
// Do not try searching...
|
|
38
|
-
return new Response([])
|
|
38
|
+
return new Response([]);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
const match = {
|
|
42
|
-
sign:
|
|
43
|
-
value: query +
|
|
44
|
-
mode:
|
|
42
|
+
sign: 'MATCH',
|
|
43
|
+
value: query + '*', // We replace special operators in boolean mode with spaces since special characters aren't indexed anyway
|
|
44
|
+
mode: 'BOOLEAN',
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
// 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
|
|
@@ -50,11 +50,11 @@ export class SearchOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
50
50
|
sort: [
|
|
51
51
|
{
|
|
52
52
|
column: { searchIndex: match },
|
|
53
|
-
direction:
|
|
54
|
-
}
|
|
55
|
-
]
|
|
53
|
+
direction: 'DESC',
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
56
|
});
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
if (request.request.getVersion() < 169) {
|
|
59
59
|
return new Response(organizations.map(o => OrganizationSimple.create(o)));
|
|
60
60
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import { AnyDecoder, AutoEncoder, Decoder, field, StringDecoder } from '@simonbackx/simple-encoding';
|
|
3
2
|
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
4
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
@@ -13,33 +12,33 @@ class Body extends AutoEncoder {
|
|
|
13
12
|
* The account id (internal id, not the stripe id)
|
|
14
13
|
*/
|
|
15
14
|
@field({ decoder: StringDecoder })
|
|
16
|
-
type: string
|
|
15
|
+
type: string;
|
|
17
16
|
|
|
18
17
|
@field({ decoder: StringDecoder })
|
|
19
|
-
id: string
|
|
18
|
+
id: string;
|
|
20
19
|
|
|
21
20
|
/**
|
|
22
21
|
* Set for connect events
|
|
23
22
|
*/
|
|
24
23
|
@field({ decoder: StringDecoder, nullable: true, optional: true })
|
|
25
|
-
account: string|null = null
|
|
24
|
+
account: string | null = null;
|
|
26
25
|
|
|
27
26
|
@field({ decoder: AnyDecoder })
|
|
28
|
-
data: any
|
|
27
|
+
data: any;
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
type Query = undefined
|
|
32
|
-
type ResponseBody = undefined
|
|
30
|
+
type Query = undefined;
|
|
31
|
+
type ResponseBody = undefined;
|
|
33
32
|
|
|
34
33
|
export class StripeWebookEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
35
|
-
bodyDecoder = Body as Decoder<Body
|
|
34
|
+
bodyDecoder = Body as Decoder<Body>;
|
|
36
35
|
|
|
37
36
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
38
|
-
if (request.method !==
|
|
37
|
+
if (request.method !== 'POST') {
|
|
39
38
|
return [false];
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
const params = Endpoint.parseParameters(request.url,
|
|
41
|
+
const params = Endpoint.parseParameters(request.url, '/stripe/webhooks', {});
|
|
43
42
|
|
|
44
43
|
if (params) {
|
|
45
44
|
return [true, params as Params];
|
|
@@ -49,104 +48,109 @@ export class StripeWebookEndpoint extends Endpoint<Params, Query, Body, Response
|
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
52
|
-
console.log(
|
|
51
|
+
console.log('Received Stripe Webhook', request.body.type);
|
|
53
52
|
|
|
54
53
|
// Verify webhook signature and extract the event.
|
|
55
54
|
// See https://stripe.com/docs/webhooks/signatures for more information.
|
|
56
55
|
let event;
|
|
57
56
|
try {
|
|
58
|
-
const stripe = StripeHelper.getInstance()
|
|
57
|
+
const stripe = StripeHelper.getInstance();
|
|
59
58
|
const sig = request.headers['stripe-signature'];
|
|
60
59
|
if (!sig) {
|
|
61
60
|
throw new SimpleError({
|
|
62
|
-
code:
|
|
63
|
-
message:
|
|
64
|
-
statusCode: 400
|
|
65
|
-
})
|
|
61
|
+
code: 'invalid_signature',
|
|
62
|
+
message: 'Invalid signature',
|
|
63
|
+
statusCode: 400,
|
|
64
|
+
});
|
|
66
65
|
}
|
|
67
|
-
const secret = request.body.account ? STAMHOOFD.STRIPE_CONNECT_ENDPOINT_SECRET : STAMHOOFD.STRIPE_ENDPOINT_SECRET
|
|
66
|
+
const secret = request.body.account ? STAMHOOFD.STRIPE_CONNECT_ENDPOINT_SECRET : STAMHOOFD.STRIPE_ENDPOINT_SECRET;
|
|
68
67
|
event = await stripe.webhooks.constructEventAsync(await request.request.bodyPromise!, sig, secret);
|
|
69
|
-
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
70
|
throw new SimpleError({
|
|
71
|
-
code:
|
|
72
|
-
message:
|
|
73
|
-
statusCode: 400
|
|
74
|
-
})
|
|
71
|
+
code: 'invalid_signature',
|
|
72
|
+
message: 'Invalid signature',
|
|
73
|
+
statusCode: 400,
|
|
74
|
+
});
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
// Check type
|
|
78
78
|
switch (request.body.type) {
|
|
79
|
-
case
|
|
79
|
+
case 'account.updated': {
|
|
80
80
|
console.log(event);
|
|
81
81
|
const account = request.body.data.object;
|
|
82
82
|
if (account && account.id) {
|
|
83
83
|
const id = account.id as string;
|
|
84
|
-
const [model] = await StripeAccount.where({accountId: id}, {limit: 1});
|
|
84
|
+
const [model] = await StripeAccount.where({ accountId: id }, { limit: 1 });
|
|
85
85
|
if (model) {
|
|
86
|
-
model.setMetaFromStripeAccount(account)
|
|
87
|
-
await model.save()
|
|
88
|
-
}
|
|
89
|
-
|
|
86
|
+
model.setMetaFromStripeAccount(account);
|
|
87
|
+
await model.save();
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
console.warn('Could not find stripe account with id', id);
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
break;
|
|
93
94
|
}
|
|
94
|
-
case
|
|
95
|
-
case
|
|
96
|
-
case
|
|
97
|
-
case
|
|
98
|
-
case
|
|
99
|
-
case
|
|
100
|
-
case
|
|
101
|
-
case
|
|
95
|
+
case 'payment_intent.amount_capturable_updated':
|
|
96
|
+
case 'payment_intent.canceled':
|
|
97
|
+
case 'payment_intent.created':
|
|
98
|
+
case 'payment_intent.partially_funded':
|
|
99
|
+
case 'payment_intent.payment_failed':
|
|
100
|
+
case 'payment_intent.processing':
|
|
101
|
+
case 'payment_intent.requires_action':
|
|
102
|
+
case 'payment_intent.succeeded': {
|
|
102
103
|
const intentId = request.body.data.object.id;
|
|
103
|
-
|
|
104
|
-
if (intentId && typeof intentId ===
|
|
105
|
-
await this.updateIntent(intentId)
|
|
104
|
+
|
|
105
|
+
if (intentId && typeof intentId === 'string') {
|
|
106
|
+
await this.updateIntent(intentId);
|
|
106
107
|
}
|
|
107
108
|
break;
|
|
108
109
|
}
|
|
109
|
-
case
|
|
110
|
-
case
|
|
111
|
-
case
|
|
112
|
-
case
|
|
110
|
+
case 'checkout.session.async_payment_failed':
|
|
111
|
+
case 'checkout.session.async_payment_succeeded':
|
|
112
|
+
case 'checkout.session.completed':
|
|
113
|
+
case 'checkout.session.expired': {
|
|
113
114
|
const checkoutId = request.body.data.object.id;
|
|
114
|
-
const [model] = await StripeCheckoutSession.where({stripeSessionId: checkoutId}, {limit: 1})
|
|
115
|
+
const [model] = await StripeCheckoutSession.where({ stripeSessionId: checkoutId }, { limit: 1 });
|
|
115
116
|
if (model && model.organizationId) {
|
|
116
|
-
const organization = await Organization.getByID(model.organizationId)
|
|
117
|
+
const organization = await Organization.getByID(model.organizationId);
|
|
117
118
|
if (organization) {
|
|
118
|
-
await ExchangePaymentEndpoint.pollStatus(model.paymentId, organization)
|
|
119
|
-
}
|
|
120
|
-
|
|
119
|
+
await ExchangePaymentEndpoint.pollStatus(model.paymentId, organization);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
console.warn('Could not find organization with id', model.organizationId);
|
|
121
123
|
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
console.warn('Could not find stripe checkout session with id', checkoutId);
|
|
124
127
|
}
|
|
125
128
|
break;
|
|
126
129
|
}
|
|
127
130
|
// Listen for charge changes (transaction fees will be added here, after the payment intent succeeded)
|
|
128
|
-
case
|
|
129
|
-
case
|
|
130
|
-
case
|
|
131
|
-
case
|
|
132
|
-
case
|
|
133
|
-
case
|
|
134
|
-
case
|
|
135
|
-
case
|
|
136
|
-
case
|
|
137
|
-
case
|
|
138
|
-
case
|
|
139
|
-
case
|
|
131
|
+
case 'charge.captured':
|
|
132
|
+
case 'charge.expired':
|
|
133
|
+
case 'charge.failed':
|
|
134
|
+
case 'charge.pending':
|
|
135
|
+
case 'charge.refunded':
|
|
136
|
+
case 'charge.succeeded':
|
|
137
|
+
case 'charge.dispute.created':
|
|
138
|
+
case 'charge.dispute.updated':
|
|
139
|
+
case 'charge.dispute.closed':
|
|
140
|
+
case 'charge.refund.updated':
|
|
141
|
+
case 'charge.refund.succeeded':
|
|
142
|
+
case 'charge.updated': {
|
|
140
143
|
const intentId = request.body.data.object.payment_intent;
|
|
141
|
-
if (intentId && typeof intentId ===
|
|
142
|
-
await this.updateIntent(intentId)
|
|
143
|
-
}
|
|
144
|
-
|
|
144
|
+
if (intentId && typeof intentId === 'string') {
|
|
145
|
+
await this.updateIntent(intentId);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
console.log('Received charge event without payment intent', request.body);
|
|
145
149
|
}
|
|
146
150
|
break;
|
|
147
151
|
}
|
|
148
152
|
default: {
|
|
149
|
-
console.log(
|
|
153
|
+
console.log('Unhandled stripe webhook type', request.body.type);
|
|
150
154
|
break;
|
|
151
155
|
}
|
|
152
156
|
}
|
|
@@ -154,17 +158,19 @@ export class StripeWebookEndpoint extends Endpoint<Params, Query, Body, Response
|
|
|
154
158
|
}
|
|
155
159
|
|
|
156
160
|
async updateIntent(intentId: string) {
|
|
157
|
-
console.log(
|
|
158
|
-
const [model] = await StripePaymentIntent.where({stripeIntentId: intentId}, {limit: 1})
|
|
161
|
+
console.log('[Webooks] Updating intent', intentId);
|
|
162
|
+
const [model] = await StripePaymentIntent.where({ stripeIntentId: intentId }, { limit: 1 });
|
|
159
163
|
if (model && model.organizationId) {
|
|
160
|
-
const organization = await Organization.getByID(model.organizationId)
|
|
164
|
+
const organization = await Organization.getByID(model.organizationId);
|
|
161
165
|
if (organization) {
|
|
162
|
-
await ExchangePaymentEndpoint.pollStatus(model.paymentId, organization)
|
|
163
|
-
} else {
|
|
164
|
-
console.warn("Could not find organization with id", model.organizationId)
|
|
166
|
+
await ExchangePaymentEndpoint.pollStatus(model.paymentId, organization);
|
|
165
167
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
+
else {
|
|
169
|
+
console.warn('Could not find organization with id', model.organizationId);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
console.warn('Could not find stripe payment intent with id', intentId);
|
|
168
174
|
}
|
|
169
175
|
}
|
|
170
176
|
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
1
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { User } from '@stamhoofd/models';
|
|
3
|
-
import { User as UserStruct } from
|
|
3
|
+
import { User as UserStruct } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
|
-
import { Context } from
|
|
6
|
-
import { AuthenticatedStructures } from
|
|
5
|
+
import { Context } from '../../../helpers/Context';
|
|
6
|
+
import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
|
|
7
7
|
type Params = Record<string, never>;
|
|
8
8
|
type Query = undefined;
|
|
9
|
-
type Body = undefined
|
|
10
|
-
type ResponseBody = UserStruct[]
|
|
9
|
+
type Body = undefined;
|
|
10
|
+
type ResponseBody = UserStruct[];
|
|
11
11
|
|
|
12
12
|
export class GetPlatformAdminsEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
13
13
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
14
|
-
if (request.method
|
|
14
|
+
if (request.method !== 'GET') {
|
|
15
15
|
return [false];
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const params = Endpoint.parseParameters(request.url,
|
|
18
|
+
const params = Endpoint.parseParameters(request.url, '/platform/admins', {});
|
|
19
19
|
|
|
20
20
|
if (params) {
|
|
21
21
|
return [true, params as Params];
|
|
@@ -24,22 +24,22 @@ export class GetPlatformAdminsEndpoint extends Endpoint<Params, Query, Body, Res
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
async handle(_: DecodedRequest<Params, Query, Body>) {
|
|
27
|
-
await Context.authenticate()
|
|
27
|
+
await Context.authenticate();
|
|
28
28
|
|
|
29
29
|
// Fast throw first (more in depth checking for patches later)
|
|
30
30
|
if (!Context.auth.canManagePlatformAdmins()) {
|
|
31
|
-
throw Context.auth.error()
|
|
31
|
+
throw Context.auth.error();
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// Get all admins
|
|
35
|
-
let admins = await User.where({ organizationId: null, permissions: { sign:
|
|
35
|
+
let admins = await User.where({ organizationId: null, permissions: { sign: '!=', value: null } });
|
|
36
36
|
|
|
37
37
|
// Hide api accounts
|
|
38
|
-
admins = admins.filter(a => !a.isApiUser)
|
|
39
|
-
admins = admins.filter(a => !!a.permissions?.globalPermissions)
|
|
38
|
+
admins = admins.filter(a => !a.isApiUser);
|
|
39
|
+
admins = admins.filter(a => !!a.permissions?.globalPermissions);
|
|
40
40
|
|
|
41
41
|
return new Response(
|
|
42
|
-
await AuthenticatedStructures.usersWithMembers(admins)
|
|
42
|
+
await AuthenticatedStructures.usersWithMembers(admins),
|
|
43
43
|
);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
2
|
-
import { Platform } from
|
|
3
|
-
import { Platform as PlatformStruct } from
|
|
1
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
2
|
+
import { Platform } from '@stamhoofd/models';
|
|
3
|
+
import { Platform as PlatformStruct } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
|
-
import { Context } from
|
|
5
|
+
import { Context } from '../../../helpers/Context';
|
|
6
6
|
|
|
7
7
|
type Params = Record<string, never>;
|
|
8
8
|
type Query = undefined;
|
|
9
|
-
type Body = undefined
|
|
9
|
+
type Body = undefined;
|
|
10
10
|
type ResponseBody = PlatformStruct;
|
|
11
11
|
|
|
12
12
|
export class GetPlatformEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
13
13
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
14
|
-
if (request.method
|
|
14
|
+
if (request.method !== 'GET') {
|
|
15
15
|
return [false];
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const params = Endpoint.parseParameters(request.url,
|
|
18
|
+
const params = Endpoint.parseParameters(request.url, '/platform', {});
|
|
19
19
|
|
|
20
20
|
if (params) {
|
|
21
21
|
return [true, params as Params];
|
|
@@ -24,16 +24,16 @@ export class GetPlatformEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
async handle(_: DecodedRequest<Params, Query, Body>) {
|
|
27
|
-
await Context.optionalAuthenticate({allowWithoutAccount: false})
|
|
27
|
+
await Context.optionalAuthenticate({ allowWithoutAccount: false });
|
|
28
28
|
|
|
29
29
|
if (Context.optionalAuth?.hasSomePlatformAccess()) {
|
|
30
|
-
const platform = await Platform.getSharedPrivateStruct()
|
|
30
|
+
const platform = await Platform.getSharedPrivateStruct();
|
|
31
31
|
if (!platform.privateConfig) {
|
|
32
|
-
throw new Error(
|
|
32
|
+
throw new Error('Private config not found');
|
|
33
33
|
}
|
|
34
34
|
return new Response(platform);
|
|
35
35
|
}
|
|
36
|
-
const platform = await Platform.getSharedStruct()
|
|
36
|
+
const platform = await Platform.getSharedStruct();
|
|
37
37
|
return new Response(platform);
|
|
38
38
|
}
|
|
39
39
|
}
|