@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,267 +1,273 @@
|
|
|
1
|
-
import { Database } from
|
|
2
|
-
import { ArrayDecoder, AutoEncoder, Decoder, field, ObjectData, StringDecoder } from
|
|
3
|
-
import { SimpleError } from
|
|
4
|
-
import { City, PostalCode, Street } from
|
|
5
|
-
import { Address, Country, ValidatedAddress } from
|
|
6
|
-
import { sleep, StringCompare } from
|
|
7
|
-
import axios from
|
|
8
|
-
import { v4 as uuidv4 } from
|
|
1
|
+
import { Database } from '@simonbackx/simple-database';
|
|
2
|
+
import { ArrayDecoder, AutoEncoder, Decoder, field, ObjectData, StringDecoder } from '@simonbackx/simple-encoding';
|
|
3
|
+
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
|
+
import { City, PostalCode, Street } from '@stamhoofd/models';
|
|
5
|
+
import { Address, Country, ValidatedAddress } from '@stamhoofd/structures';
|
|
6
|
+
import { sleep, StringCompare } from '@stamhoofd/utility';
|
|
7
|
+
import axios from 'axios';
|
|
8
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
9
9
|
|
|
10
10
|
export class AddressValidatorStatic {
|
|
11
11
|
// TODO: hold street cache
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
async validate(address: Address): Promise<ValidatedAddress> {
|
|
14
|
-
address = address.clone()
|
|
15
|
-
let postalCode = address.postalCode
|
|
14
|
+
address = address.clone();
|
|
15
|
+
let postalCode = address.postalCode;
|
|
16
16
|
if (address.country == Country.Netherlands) {
|
|
17
17
|
// Check if we have the right syntax
|
|
18
|
-
const stripped = postalCode.replace(/\s/g, '')
|
|
19
|
-
if (stripped.length
|
|
18
|
+
const stripped = postalCode.replace(/\s/g, '');
|
|
19
|
+
if (stripped.length !== 6) {
|
|
20
20
|
throw new SimpleError({
|
|
21
|
-
code:
|
|
22
|
-
message:
|
|
21
|
+
code: 'invalid_field',
|
|
22
|
+
message: 'Invalid postal code format (NL)',
|
|
23
23
|
human: "Ongeldig postcode formaat, voer in zoals '8011 PK'",
|
|
24
|
-
field:
|
|
25
|
-
})
|
|
24
|
+
field: 'postalCode',
|
|
25
|
+
});
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
const numbers = stripped.slice(0, 4)
|
|
28
|
+
const numbers = stripped.slice(0, 4);
|
|
29
29
|
if (!/[0-9]{4}/.test(numbers)) {
|
|
30
30
|
throw new SimpleError({
|
|
31
|
-
code:
|
|
32
|
-
message:
|
|
31
|
+
code: 'invalid_field',
|
|
32
|
+
message: 'Invalid postal code format (NL)',
|
|
33
33
|
human: "Ongeldig postcode formaat, voer in zoals '8011 PK'",
|
|
34
|
-
field:
|
|
35
|
-
})
|
|
34
|
+
field: 'postalCode',
|
|
35
|
+
});
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// Don't do validation on last letters
|
|
39
|
-
postalCode = numbers
|
|
40
|
-
}
|
|
41
|
-
|
|
39
|
+
postalCode = numbers;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
postalCode = postalCode.trim();
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
if (postalCode.length == 0) {
|
|
45
|
-
const numbers = address.city.substring(0, 4)
|
|
46
|
+
const numbers = address.city.substring(0, 4);
|
|
46
47
|
if (!/[0-9]{4}/.test(numbers)) {
|
|
47
|
-
postalCode = numbers
|
|
48
|
-
address.city = address.city.substring(4).trim()
|
|
49
|
-
}
|
|
48
|
+
postalCode = numbers;
|
|
49
|
+
address.city = address.city.substring(4).trim();
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
50
52
|
throw new SimpleError({
|
|
51
|
-
code:
|
|
52
|
-
message:
|
|
53
|
-
human:
|
|
54
|
-
field:
|
|
55
|
-
})
|
|
53
|
+
code: 'invalid_field',
|
|
54
|
+
message: 'Postal code is required',
|
|
55
|
+
human: 'Voer een postcode in',
|
|
56
|
+
field: 'postalCode',
|
|
57
|
+
});
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
if (address.country !== Country.Belgium && address.country !== Country.Netherlands) {
|
|
60
62
|
// No validation for other countries
|
|
61
|
-
return ValidatedAddress.create(Object.assign({ ...
|
|
63
|
+
return ValidatedAddress.create(Object.assign({ ...address }, {
|
|
62
64
|
postalCode: address.postalCode,
|
|
63
65
|
city: address.city,
|
|
64
66
|
cityId: 'unknown',
|
|
65
67
|
parentCityId: null,
|
|
66
68
|
provinceId: 'unknown',
|
|
67
|
-
}))
|
|
69
|
+
}));
|
|
68
70
|
}
|
|
69
|
-
|
|
70
|
-
const city = await PostalCode.getCity(postalCode, address.city, address.country)
|
|
71
|
+
|
|
72
|
+
const city = await PostalCode.getCity(postalCode, address.city, address.country);
|
|
71
73
|
|
|
72
74
|
if (!city) {
|
|
73
75
|
throw new SimpleError({
|
|
74
|
-
code:
|
|
75
|
-
message:
|
|
76
|
-
human:
|
|
77
|
-
field:
|
|
78
|
-
})
|
|
76
|
+
code: 'invalid_field',
|
|
77
|
+
message: 'Invalid postal code or city',
|
|
78
|
+
human: 'Deze postcode en/of gemeente bestaat niet, kijk je even na op een typfout?',
|
|
79
|
+
field: 'postalCode',
|
|
80
|
+
});
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
// Validate street and try to correct it
|
|
82
84
|
if (address.country === Country.Belgium) {
|
|
83
85
|
// Also validate the street
|
|
84
|
-
let streets = await Street.where({ cityId: city.parentCityId ?? city.id })
|
|
86
|
+
let streets = await Street.where({ cityId: city.parentCityId ?? city.id });
|
|
85
87
|
|
|
86
|
-
if (streets.length == 0 && STAMHOOFD.environment ===
|
|
87
|
-
console.log(
|
|
88
|
-
const c = await City.getByID(city.parentCityId ?? city.id)
|
|
88
|
+
if (streets.length == 0 && STAMHOOFD.environment === 'development') {
|
|
89
|
+
console.log('Forcing sync of city');
|
|
90
|
+
const c = await City.getByID(city.parentCityId ?? city.id);
|
|
89
91
|
try {
|
|
90
|
-
await this.syncCity(c!)
|
|
91
|
-
} catch (e) {
|
|
92
|
-
console.error('Ignored error while syncing city')
|
|
93
|
-
console.error(e)
|
|
92
|
+
await this.syncCity(c!);
|
|
94
93
|
}
|
|
95
|
-
|
|
94
|
+
catch (e) {
|
|
95
|
+
console.error('Ignored error while syncing city');
|
|
96
|
+
console.error(e);
|
|
97
|
+
}
|
|
98
|
+
streets = await Street.where({ cityId: city.parentCityId ?? city.id });
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
if (STAMHOOFD.environment ===
|
|
101
|
+
if (STAMHOOFD.environment === 'development' && streets.length > 0) {
|
|
99
102
|
// First search by typo count
|
|
100
|
-
let bestScore = 0
|
|
101
|
-
let bestStreet: Street | undefined = undefined
|
|
103
|
+
let bestScore = 0;
|
|
104
|
+
let bestStreet: Street | undefined = undefined;
|
|
102
105
|
for (const street of streets) {
|
|
103
|
-
const score = StringCompare.typoCount(street.name, address.street)
|
|
106
|
+
const score = StringCompare.typoCount(street.name, address.street);
|
|
104
107
|
if ((bestStreet === undefined || score < bestScore)) {
|
|
105
|
-
bestScore = score
|
|
106
|
-
bestStreet = street
|
|
108
|
+
bestScore = score;
|
|
109
|
+
bestStreet = street;
|
|
107
110
|
}
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
if (bestStreet && bestScore < 3) {
|
|
111
|
-
address.street = bestStreet.name
|
|
112
|
-
}
|
|
114
|
+
address.street = bestStreet.name;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
113
117
|
// Search for the street
|
|
114
|
-
bestScore = 0
|
|
115
|
-
bestStreet = undefined
|
|
118
|
+
bestScore = 0;
|
|
119
|
+
bestStreet = undefined;
|
|
116
120
|
for (const street of streets) {
|
|
117
|
-
const score = StringCompare.compare(street.name, address.street)
|
|
121
|
+
const score = StringCompare.compare(street.name, address.street);
|
|
118
122
|
if ((bestStreet === undefined || score > bestScore)) {
|
|
119
|
-
bestScore = score
|
|
120
|
-
bestStreet = street
|
|
123
|
+
bestScore = score;
|
|
124
|
+
bestStreet = street;
|
|
121
125
|
}
|
|
122
126
|
}
|
|
123
127
|
|
|
124
|
-
if (!bestStreet || bestScore < 3 || bestScore < bestStreet.name.length/3) {
|
|
128
|
+
if (!bestStreet || bestScore < 3 || bestScore < bestStreet.name.length / 3) {
|
|
125
129
|
throw new SimpleError({
|
|
126
|
-
code:
|
|
127
|
-
message:
|
|
128
|
-
human:
|
|
129
|
-
field:
|
|
130
|
-
})
|
|
130
|
+
code: 'invalid_field',
|
|
131
|
+
message: 'Invalid street',
|
|
132
|
+
human: 'Deze straat bestaat niet, kijk je deze even na op fouten? Formuleer de naam zonder afkortingen.',
|
|
133
|
+
field: 'street',
|
|
134
|
+
});
|
|
131
135
|
}
|
|
132
136
|
|
|
133
137
|
throw new SimpleError({
|
|
134
|
-
code:
|
|
135
|
-
message:
|
|
138
|
+
code: 'invalid_field',
|
|
139
|
+
message: 'Invalid street, do you mean ' + bestStreet.name + '?',
|
|
136
140
|
human: "Deze straat bestaat niet, bedoel je '" + bestStreet.name + "'?",
|
|
137
|
-
field:
|
|
138
|
-
})
|
|
141
|
+
field: 'street',
|
|
142
|
+
});
|
|
139
143
|
}
|
|
140
|
-
}
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
141
146
|
// Skip validation for some regions that don't support validation
|
|
142
147
|
}
|
|
143
148
|
}
|
|
144
149
|
|
|
145
|
-
return ValidatedAddress.create(Object.assign({ ...
|
|
150
|
+
return ValidatedAddress.create(Object.assign({ ...address }, {
|
|
146
151
|
postalCode: address.country === Country.Belgium ? postalCode : address.postalCode,
|
|
147
152
|
city: city.name, // override misspelled addresses
|
|
148
153
|
cityId: city.id,
|
|
149
154
|
parentCityId: city.parentCityId,
|
|
150
155
|
provinceId: city.provinceId,
|
|
151
|
-
}))
|
|
156
|
+
}));
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
async downloadStreets(country: Country, city: string): Promise<string[]> {
|
|
155
|
-
let url: string | undefined =
|
|
156
|
-
const streetNames: string[] = []
|
|
160
|
+
let url: string | undefined = 'https://api.basisregisters.vlaanderen.be/v2/straatnamen?gemeentenaam=' + encodeURIComponent(city);
|
|
161
|
+
const streetNames: string[] = [];
|
|
157
162
|
|
|
158
163
|
try {
|
|
159
164
|
while (url) {
|
|
160
165
|
const response = await axios.request({
|
|
161
|
-
method:
|
|
166
|
+
method: 'GET',
|
|
162
167
|
url,
|
|
163
168
|
headers: {
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
})
|
|
169
|
+
Accept: 'application/ld+json',
|
|
170
|
+
},
|
|
171
|
+
});
|
|
167
172
|
|
|
168
173
|
// TypeScript is going insane here, hence the weird type casting
|
|
169
174
|
const result = new ObjectData(response.data, { version: 0 }).decode(StraatnamenResult as Decoder<StraatnamenResult>) as any as StraatnamenResult;
|
|
170
175
|
const streets = result.straatnamen.map(street => street.straatnaam.geografischeNaam.spelling);
|
|
171
176
|
|
|
172
177
|
streetNames.push(...streets);
|
|
173
|
-
url = result.volgende
|
|
178
|
+
url = result.volgende;
|
|
174
179
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
console.error(e.response.data)
|
|
178
|
-
throw new Error(
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
console.error(e.response.data);
|
|
183
|
+
throw new Error('Failed to fetch streets');
|
|
179
184
|
}
|
|
180
185
|
|
|
181
|
-
return streetNames
|
|
186
|
+
return streetNames;
|
|
182
187
|
}
|
|
183
188
|
|
|
184
189
|
async syncCity(city: City): Promise<void> {
|
|
185
|
-
const streetNames = await this.downloadStreets(city.country, city.name)
|
|
190
|
+
const streetNames = await this.downloadStreets(city.country, city.name);
|
|
186
191
|
if (streetNames.length == 0) {
|
|
187
|
-
return
|
|
192
|
+
return;
|
|
188
193
|
}
|
|
189
|
-
|
|
190
|
-
await Database.delete(
|
|
191
|
-
await Database.insert(
|
|
194
|
+
|
|
195
|
+
await Database.delete('DELETE from `streets` WHERE `cityId` = ?', [city.id]);
|
|
196
|
+
await Database.insert('INSERT INTO `streets` (`id`, `name`, `cityId`) VALUES ?', [streetNames.map(street => [uuidv4(), street, city.id])]);
|
|
192
197
|
}
|
|
193
198
|
|
|
194
199
|
async syncAll(): Promise<void> {
|
|
195
|
-
const cities = await City.where({ country: Country.Belgium, parentCityId: null })
|
|
200
|
+
const cities = await City.where({ country: Country.Belgium, parentCityId: null });
|
|
196
201
|
for (const city of cities) {
|
|
197
|
-
await this.syncCity(city)
|
|
202
|
+
await this.syncCity(city);
|
|
198
203
|
|
|
199
204
|
// Rate limit
|
|
200
|
-
await sleep(1000)
|
|
205
|
+
await sleep(1000);
|
|
201
206
|
}
|
|
202
207
|
}
|
|
203
208
|
|
|
204
209
|
getSlowSync(): () => Promise<void> {
|
|
205
|
-
let lastFullCitySync: Date | null = null
|
|
206
|
-
let lastCityId =
|
|
210
|
+
let lastFullCitySync: Date | null = null;
|
|
211
|
+
let lastCityId = '';
|
|
207
212
|
async function syncNext() {
|
|
208
213
|
// Wait 24 hours between every full update
|
|
209
214
|
if (lastFullCitySync && lastFullCitySync > new Date(new Date().getTime() - 24 * 60 * 60 * 1000)) {
|
|
210
|
-
console.log(
|
|
211
|
-
return
|
|
215
|
+
console.log('Skip city sync');
|
|
216
|
+
return;
|
|
212
217
|
}
|
|
213
|
-
|
|
214
|
-
const cities = await City.where({
|
|
218
|
+
|
|
219
|
+
const cities = await City.where({
|
|
215
220
|
id: { sign: '>', value: lastCityId },
|
|
216
|
-
country: Country.Belgium,
|
|
217
|
-
parentCityId: null
|
|
221
|
+
country: Country.Belgium,
|
|
222
|
+
parentCityId: null,
|
|
218
223
|
}, {
|
|
219
224
|
limit: 1,
|
|
220
|
-
sort: [
|
|
221
|
-
})
|
|
225
|
+
sort: ['id'],
|
|
226
|
+
});
|
|
222
227
|
|
|
223
228
|
if (cities.length == 0) {
|
|
224
229
|
// Wait an half hour before starting again
|
|
225
|
-
lastCityId =
|
|
226
|
-
lastFullCitySync = new Date()
|
|
227
|
-
return
|
|
230
|
+
lastCityId = '';
|
|
231
|
+
lastFullCitySync = new Date();
|
|
232
|
+
return;
|
|
228
233
|
}
|
|
229
234
|
|
|
230
235
|
for (const city of cities) {
|
|
231
236
|
try {
|
|
232
|
-
await this.syncCity(city)
|
|
233
|
-
}
|
|
234
|
-
|
|
237
|
+
await this.syncCity(city);
|
|
238
|
+
}
|
|
239
|
+
catch (e) {
|
|
240
|
+
console.error('Failed city sync for ' + city.name, e);
|
|
235
241
|
}
|
|
236
242
|
}
|
|
237
243
|
|
|
238
|
-
lastCityId = cities[cities.length - 1].id
|
|
244
|
+
lastCityId = cities[cities.length - 1].id;
|
|
239
245
|
}
|
|
240
246
|
|
|
241
|
-
return syncNext
|
|
247
|
+
return syncNext;
|
|
242
248
|
}
|
|
243
249
|
}
|
|
244
250
|
class GeografischeNaam extends AutoEncoder {
|
|
245
251
|
@field({ decoder: StringDecoder })
|
|
246
|
-
spelling: string
|
|
252
|
+
spelling: string;
|
|
247
253
|
}
|
|
248
254
|
|
|
249
255
|
class Straatnaam extends AutoEncoder {
|
|
250
256
|
@field({ decoder: GeografischeNaam })
|
|
251
|
-
geografischeNaam: GeografischeNaam
|
|
257
|
+
geografischeNaam: GeografischeNaam;
|
|
252
258
|
}
|
|
253
259
|
|
|
254
260
|
class StraatnaamResult extends AutoEncoder {
|
|
255
261
|
@field({ decoder: Straatnaam })
|
|
256
|
-
straatnaam: Straatnaam
|
|
262
|
+
straatnaam: Straatnaam;
|
|
257
263
|
}
|
|
258
264
|
|
|
259
265
|
class StraatnamenResult extends AutoEncoder {
|
|
260
266
|
@field({ decoder: new ArrayDecoder(StraatnaamResult) })
|
|
261
|
-
straatnamen: StraatnaamResult[]
|
|
267
|
+
straatnamen: StraatnaamResult[];
|
|
262
268
|
|
|
263
269
|
@field({ decoder: StringDecoder, optional: true })
|
|
264
|
-
volgende?: string
|
|
270
|
+
volgende?: string;
|
|
265
271
|
}
|
|
266
272
|
|
|
267
|
-
export const AddressValidator = new AddressValidatorStatic()
|
|
273
|
+
export const AddressValidator = new AddressValidatorStatic();
|