@stamhoofd/models 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/dist/src/factories/AddressFactory.d.ts +3 -4
- package/dist/src/factories/AddressFactory.d.ts.map +1 -1
- package/dist/src/factories/AddressFactory.js +13 -13
- package/dist/src/factories/EmergencyContactFactory.d.ts +3 -4
- package/dist/src/factories/EmergencyContactFactory.d.ts.map +1 -1
- package/dist/src/factories/EmergencyContactFactory.js +27 -27
- package/dist/src/factories/EmergencyContactFactory.js.map +1 -1
- package/dist/src/factories/GroupFactory.d.ts +4 -4
- package/dist/src/factories/GroupFactory.d.ts.map +1 -1
- package/dist/src/factories/GroupFactory.js +8 -8
- package/dist/src/factories/GroupFactory.js.map +1 -1
- package/dist/src/factories/MemberFactory.d.ts +4 -4
- package/dist/src/factories/MemberFactory.d.ts.map +1 -1
- package/dist/src/factories/MemberFactory.js +17 -17
- package/dist/src/factories/MemberFactory.js.map +1 -1
- package/dist/src/factories/OrganizationFactory.d.ts +4 -4
- package/dist/src/factories/OrganizationFactory.js +8 -8
- package/dist/src/factories/OrganizationFactory.js.map +1 -1
- package/dist/src/factories/ParentFactory.d.ts +1 -1
- package/dist/src/factories/ParentFactory.js +19 -19
- package/dist/src/factories/ParentFactory.js.map +1 -1
- package/dist/src/factories/RecordFactory.d.ts +2 -3
- package/dist/src/factories/RecordFactory.d.ts.map +1 -1
- package/dist/src/factories/RecordFactory.js +1 -1
- package/dist/src/factories/RecordFactory.js.map +1 -1
- package/dist/src/factories/RegisterCodeFactory.d.ts +2 -2
- package/dist/src/factories/RegisterCodeFactory.d.ts.map +1 -1
- package/dist/src/factories/RegisterCodeFactory.js +2 -2
- package/dist/src/factories/RegistrationFactory.d.ts +3 -3
- package/dist/src/factories/RegistrationFactory.d.ts.map +1 -1
- package/dist/src/factories/RegistrationFactory.js.map +1 -1
- package/dist/src/factories/RegistrationPeriodFactory.d.ts +2 -2
- package/dist/src/factories/RegistrationPeriodFactory.js.map +1 -1
- package/dist/src/factories/UserFactory.d.ts +3 -3
- package/dist/src/factories/UserFactory.d.ts.map +1 -1
- package/dist/src/factories/UserFactory.js +3 -3
- package/dist/src/factories/UserFactory.js.map +1 -1
- package/dist/src/factories/WebshopFactory.d.ts +4 -4
- package/dist/src/factories/WebshopFactory.d.ts.map +1 -1
- package/dist/src/factories/WebshopFactory.js +1 -1
- package/dist/src/factories/WebshopFactory.js.map +1 -1
- package/dist/src/helpers/DNSValidator.d.ts +1 -1
- package/dist/src/helpers/DNSValidator.d.ts.map +1 -1
- package/dist/src/helpers/DNSValidator.js +33 -33
- package/dist/src/helpers/DNSValidator.js.map +1 -1
- package/dist/src/helpers/EmailBuilder.d.ts +10 -10
- package/dist/src/helpers/EmailBuilder.d.ts.map +1 -1
- package/dist/src/helpers/EmailBuilder.js +34 -34
- package/dist/src/helpers/EmailBuilder.js.map +1 -1
- package/dist/src/helpers/GroupBuilder.d.ts.map +1 -1
- package/dist/src/helpers/GroupBuilder.js +57 -57
- package/dist/src/helpers/GroupBuilder.js.map +1 -1
- package/dist/src/helpers/Handlebars.d.ts.map +1 -1
- package/dist/src/helpers/Handlebars.js +29 -29
- package/dist/src/helpers/Handlebars.js.map +1 -1
- package/dist/src/helpers/MemberMerger.d.ts +1 -1
- package/dist/src/helpers/MemberMerger.d.ts.map +1 -1
- package/dist/src/helpers/MemberMerger.js +33 -33
- package/dist/src/helpers/MemberMerger.js.map +1 -1
- package/dist/src/helpers/MemberMerger.test.js +194 -194
- package/dist/src/helpers/MemberMerger.test.js.map +1 -1
- package/dist/src/helpers/RateLimiter.d.ts.map +1 -1
- package/dist/src/helpers/RateLimiter.js +2 -2
- package/dist/src/helpers/RateLimiter.js.map +1 -1
- package/dist/src/helpers/SetupStepsUpdater.d.ts +22 -0
- package/dist/src/helpers/SetupStepsUpdater.d.ts.map +1 -0
- package/dist/src/helpers/SetupStepsUpdater.js +255 -0
- package/dist/src/helpers/SetupStepsUpdater.js.map +1 -0
- package/dist/src/helpers/WebshopCounter.d.ts +1 -1
- package/dist/src/helpers/WebshopCounter.d.ts.map +1 -1
- package/dist/src/helpers/WebshopCounter.js +1 -1
- package/dist/src/helpers/WebshopCounter.js.map +1 -1
- package/dist/src/helpers/WebshopCounter.test.js +6 -6
- package/dist/src/helpers/WebshopCounter.test.js.map +1 -1
- package/dist/src/index.d.ts +20 -19
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/migrations/1605262045-import-postcodes.js +12 -12
- package/dist/src/migrations/1605262046-import-postcodes-nl.js +10 -10
- package/dist/src/models/BalanceItem.d.ts.map +1 -1
- package/dist/src/models/BalanceItem.js +37 -37
- package/dist/src/models/BalanceItem.js.map +1 -1
- package/dist/src/models/BalanceItemPayment.d.ts.map +1 -1
- package/dist/src/models/BalanceItemPayment.js +13 -13
- package/dist/src/models/BalanceItemPayment.js.map +1 -1
- package/dist/src/models/BuckarooPayment.d.ts +1 -1
- package/dist/src/models/BuckarooPayment.d.ts.map +1 -1
- package/dist/src/models/BuckarooPayment.js +5 -5
- package/dist/src/models/BuckarooPayment.js.map +1 -1
- package/dist/src/models/CachedOutstandingBalance.d.ts.map +1 -1
- package/dist/src/models/CachedOutstandingBalance.js +37 -37
- package/dist/src/models/CachedOutstandingBalance.js.map +1 -1
- package/dist/src/models/Document.d.ts +4 -4
- package/dist/src/models/Document.d.ts.map +1 -1
- package/dist/src/models/Document.js +27 -27
- package/dist/src/models/Document.js.map +1 -1
- package/dist/src/models/DocumentTemplate.d.ts +4 -4
- package/dist/src/models/DocumentTemplate.d.ts.map +1 -1
- package/dist/src/models/DocumentTemplate.js +72 -72
- package/dist/src/models/DocumentTemplate.js.map +1 -1
- package/dist/src/models/Email.d.ts.map +1 -1
- package/dist/src/models/Email.js +63 -64
- package/dist/src/models/Email.js.map +1 -1
- package/dist/src/models/EmailRecipient.d.ts.map +1 -1
- package/dist/src/models/EmailRecipient.js +20 -20
- package/dist/src/models/EmailRecipient.js.map +1 -1
- package/dist/src/models/EmailTemplate.d.ts +3 -3
- package/dist/src/models/EmailTemplate.d.ts.map +1 -1
- package/dist/src/models/EmailTemplate.js +16 -16
- package/dist/src/models/EmailTemplate.js.map +1 -1
- package/dist/src/models/EmailVerificationCode.d.ts +2 -2
- package/dist/src/models/EmailVerificationCode.d.ts.map +1 -1
- package/dist/src/models/EmailVerificationCode.js +57 -55
- package/dist/src/models/EmailVerificationCode.js.map +1 -1
- package/dist/src/models/Event.d.ts +2 -2
- package/dist/src/models/Event.d.ts.map +1 -1
- package/dist/src/models/Event.js +15 -15
- package/dist/src/models/Event.js.map +1 -1
- package/dist/src/models/Group.d.ts +3 -1
- package/dist/src/models/Group.d.ts.map +1 -1
- package/dist/src/models/Group.js +46 -35
- package/dist/src/models/Group.js.map +1 -1
- package/dist/src/models/Image.d.ts +1 -1
- package/dist/src/models/Image.d.ts.map +1 -1
- package/dist/src/models/Image.js +26 -26
- package/dist/src/models/Image.js.map +1 -1
- package/dist/src/models/Member.d.ts +8 -8
- package/dist/src/models/Member.d.ts.map +1 -1
- package/dist/src/models/Member.js +60 -60
- package/dist/src/models/Member.js.map +1 -1
- package/dist/src/models/MemberPlatformMembership.d.ts +3 -3
- package/dist/src/models/MemberPlatformMembership.d.ts.map +1 -1
- package/dist/src/models/MemberPlatformMembership.js +26 -26
- package/dist/src/models/MemberPlatformMembership.js.map +1 -1
- package/dist/src/models/MemberResponsibilityRecord.d.ts.map +1 -1
- package/dist/src/models/MemberResponsibilityRecord.js +13 -13
- package/dist/src/models/MemberResponsibilityRecord.js.map +1 -1
- package/dist/src/models/MergedMember.d.ts +3 -3
- package/dist/src/models/MergedMember.d.ts.map +1 -1
- package/dist/src/models/MergedMember.js +19 -19
- package/dist/src/models/MergedMember.js.map +1 -1
- package/dist/src/models/MolliePayment.d.ts +1 -1
- package/dist/src/models/MolliePayment.d.ts.map +1 -1
- package/dist/src/models/MolliePayment.js +5 -5
- package/dist/src/models/MolliePayment.js.map +1 -1
- package/dist/src/models/MollieToken.d.ts.map +1 -1
- package/dist/src/models/MollieToken.js +60 -60
- package/dist/src/models/MollieToken.js.map +1 -1
- package/dist/src/models/OneTimeToken.d.ts +2 -2
- package/dist/src/models/OneTimeToken.d.ts.map +1 -1
- package/dist/src/models/OneTimeToken.js +13 -13
- package/dist/src/models/OneTimeToken.js.map +1 -1
- package/dist/src/models/Order.d.ts +1 -1
- package/dist/src/models/Order.d.ts.map +1 -1
- package/dist/src/models/Order.js +70 -70
- package/dist/src/models/Order.js.map +1 -1
- package/dist/src/models/Organization.d.ts +5 -5
- package/dist/src/models/Organization.d.ts.map +1 -1
- package/dist/src/models/Organization.js +127 -127
- package/dist/src/models/Organization.js.map +1 -1
- package/dist/src/models/OrganizationRegistrationPeriod.d.ts.map +1 -1
- package/dist/src/models/OrganizationRegistrationPeriod.js +15 -15
- package/dist/src/models/OrganizationRegistrationPeriod.js.map +1 -1
- package/dist/src/models/PasswordToken.d.ts +3 -3
- package/dist/src/models/PasswordToken.d.ts.map +1 -1
- package/dist/src/models/PasswordToken.js +17 -17
- package/dist/src/models/PasswordToken.js.map +1 -1
- package/dist/src/models/PayconiqPayment.d.ts +1 -1
- package/dist/src/models/PayconiqPayment.d.ts.map +1 -1
- package/dist/src/models/PayconiqPayment.js +49 -49
- package/dist/src/models/PayconiqPayment.js.map +1 -1
- package/dist/src/models/Payment.d.ts +3 -3
- package/dist/src/models/Payment.d.ts.map +1 -1
- package/dist/src/models/Payment.js +36 -36
- package/dist/src/models/Payment.js.map +1 -1
- package/dist/src/models/Platform.d.ts +2 -2
- package/dist/src/models/Platform.d.ts.map +1 -1
- package/dist/src/models/Platform.js +8 -8
- package/dist/src/models/Platform.js.map +1 -1
- package/dist/src/models/RegisterCode.d.ts +1 -1
- package/dist/src/models/RegisterCode.d.ts.map +1 -1
- package/dist/src/models/RegisterCode.js +11 -11
- package/dist/src/models/RegisterCode.js.map +1 -1
- package/dist/src/models/Registration.d.ts +1 -1
- package/dist/src/models/Registration.d.ts.map +1 -1
- package/dist/src/models/Registration.js +88 -88
- package/dist/src/models/Registration.js.map +1 -1
- package/dist/src/models/RegistrationPeriod.d.ts.map +1 -1
- package/dist/src/models/RegistrationPeriod.js +12 -12
- package/dist/src/models/RegistrationPeriod.js.map +1 -1
- package/dist/src/models/STCredit.d.ts +1 -1
- package/dist/src/models/STCredit.d.ts.map +1 -1
- package/dist/src/models/STCredit.js +12 -12
- package/dist/src/models/STCredit.js.map +1 -1
- package/dist/src/models/STInvoice.d.ts +1 -1
- package/dist/src/models/STInvoice.d.ts.map +1 -1
- package/dist/src/models/STInvoice.js +16 -16
- package/dist/src/models/STInvoice.js.map +1 -1
- package/dist/src/models/STPackage.d.ts +1 -1
- package/dist/src/models/STPackage.d.ts.map +1 -1
- package/dist/src/models/STPackage.js +39 -39
- package/dist/src/models/STPackage.js.map +1 -1
- package/dist/src/models/STPendingInvoice.d.ts +1 -1
- package/dist/src/models/STPendingInvoice.d.ts.map +1 -1
- package/dist/src/models/STPendingInvoice.js +11 -11
- package/dist/src/models/STPendingInvoice.js.map +1 -1
- package/dist/src/models/StripeAccount.d.ts.map +1 -1
- package/dist/src/models/StripeAccount.js +13 -13
- package/dist/src/models/StripeAccount.js.map +1 -1
- package/dist/src/models/StripeCheckoutSession.d.ts +1 -1
- package/dist/src/models/StripeCheckoutSession.d.ts.map +1 -1
- package/dist/src/models/StripeCheckoutSession.js +7 -7
- package/dist/src/models/StripeCheckoutSession.js.map +1 -1
- package/dist/src/models/StripePaymentIntent.d.ts +1 -1
- package/dist/src/models/StripePaymentIntent.d.ts.map +1 -1
- package/dist/src/models/StripePaymentIntent.js +7 -7
- package/dist/src/models/StripePaymentIntent.js.map +1 -1
- package/dist/src/models/Ticket.d.ts +2 -2
- package/dist/src/models/Ticket.d.ts.map +1 -1
- package/dist/src/models/Ticket.js +23 -23
- package/dist/src/models/Ticket.js.map +1 -1
- package/dist/src/models/Token.d.ts +3 -3
- package/dist/src/models/Token.d.ts.map +1 -1
- package/dist/src/models/Token.js +27 -27
- package/dist/src/models/Token.js.map +1 -1
- package/dist/src/models/Token.test.js +11 -11
- package/dist/src/models/UsedRegisterCode.d.ts +1 -1
- package/dist/src/models/UsedRegisterCode.d.ts.map +1 -1
- package/dist/src/models/UsedRegisterCode.js +10 -10
- package/dist/src/models/UsedRegisterCode.js.map +1 -1
- package/dist/src/models/User.d.ts +4 -4
- package/dist/src/models/User.d.ts.map +1 -1
- package/dist/src/models/User.js +53 -51
- package/dist/src/models/User.js.map +1 -1
- package/dist/src/models/UserPermissions.d.ts +3 -3
- package/dist/src/models/UserPermissions.d.ts.map +1 -1
- package/dist/src/models/UserPermissions.js +12 -12
- package/dist/src/models/UserPermissions.js.map +1 -1
- package/dist/src/models/Webshop.d.ts +1 -1
- package/dist/src/models/Webshop.d.ts.map +1 -1
- package/dist/src/models/Webshop.js +23 -23
- package/dist/src/models/Webshop.js.map +1 -1
- package/dist/src/models/WebshopDiscountCode.d.ts +1 -1
- package/dist/src/models/WebshopDiscountCode.d.ts.map +1 -1
- package/dist/src/models/WebshopDiscountCode.js +16 -16
- package/dist/src/models/WebshopDiscountCode.js.map +1 -1
- package/dist/src/models/addresses/City.d.ts.map +1 -1
- package/dist/src/models/addresses/City.js +9 -9
- package/dist/src/models/addresses/City.js.map +1 -1
- package/dist/src/models/addresses/PostalCode.d.ts.map +1 -1
- package/dist/src/models/addresses/PostalCode.js +11 -11
- package/dist/src/models/addresses/PostalCode.js.map +1 -1
- package/dist/src/models/addresses/PostalCode.test.js +22 -22
- package/dist/src/models/addresses/PostalCode.test.js.map +1 -1
- package/dist/src/models/addresses/Province.d.ts.map +1 -1
- package/dist/src/models/addresses/Province.js +5 -5
- package/dist/src/models/addresses/Province.js.map +1 -1
- package/dist/src/models/addresses/Street.d.ts.map +1 -1
- package/dist/src/models/addresses/Street.js +6 -6
- package/dist/src/models/addresses/Street.js.map +1 -1
- package/dist/src/models/index.d.ts +46 -46
- package/dist/src/models/index.d.ts.map +1 -1
- package/dist/src/models/index.js +0 -1
- package/dist/src/models/index.js.map +1 -1
- package/dist/src/structures/OrganizationServerMetaData.d.ts.map +1 -1
- package/dist/src/structures/OrganizationServerMetaData.js +4 -4
- package/dist/src/structures/OrganizationServerMetaData.js.map +1 -1
- package/dist/tests/jest.global.setup.d.ts.map +1 -1
- package/dist/tests/jest.global.setup.js +15 -13
- package/dist/tests/jest.global.setup.js.map +1 -1
- package/dist/tests/jest.setup.js +3 -1
- package/dist/tests/jest.setup.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +3 -3
- package/src/factories/AddressFactory.ts +17 -17
- package/src/factories/EmergencyContactFactory.ts +30 -31
- package/src/factories/GroupFactory.ts +30 -30
- package/src/factories/MemberFactory.ts +41 -38
- package/src/factories/OrganizationFactory.ts +15 -15
- package/src/factories/ParentFactory.ts +24 -24
- package/src/factories/RecordFactory.ts +5 -4
- package/src/factories/RegisterCodeFactory.ts +7 -7
- package/src/factories/RegistrationFactory.ts +16 -16
- package/src/factories/RegistrationPeriodFactory.ts +5 -5
- package/src/factories/UserFactory.ts +20 -19
- package/src/factories/WebshopFactory.ts +14 -14
- package/src/helpers/DNSValidator.ts +89 -84
- package/src/helpers/EmailBuilder.ts +141 -135
- package/src/helpers/GroupBuilder.ts +181 -181
- package/src/helpers/Handlebars.ts +57 -54
- package/src/helpers/MemberMerger.test.ts +702 -702
- package/src/helpers/MemberMerger.ts +83 -77
- package/src/helpers/RateLimiter.ts +25 -27
- package/src/helpers/SetupStepsUpdater.ts +402 -0
- package/src/helpers/WebshopCounter.test.ts +12 -12
- package/src/helpers/WebshopCounter.ts +20 -19
- package/src/index.ts +20 -19
- package/src/migrations/1605262045-import-postcodes.ts +59 -63
- package/src/migrations/1605262046-import-postcodes-nl.ts +41 -43
- package/src/models/BalanceItem.ts +173 -172
- package/src/models/BalanceItemPayment.ts +32 -33
- package/src/models/BuckarooPayment.ts +7 -7
- package/src/models/CachedOutstandingBalance.ts +98 -99
- package/src/models/Document.ts +90 -87
- package/src/models/DocumentTemplate.ts +207 -198
- package/src/models/Email.ts +198 -200
- package/src/models/EmailRecipient.ts +38 -39
- package/src/models/EmailTemplate.ts +36 -37
- package/src/models/EmailVerificationCode.ts +146 -142
- package/src/models/Event.ts +53 -53
- package/src/models/Group.ts +136 -123
- package/src/models/Image.ts +48 -48
- package/src/models/Member.ts +277 -275
- package/src/models/MemberPlatformMembership.ts +71 -71
- package/src/models/MemberResponsibilityRecord.ts +32 -32
- package/src/models/MergedMember.ts +77 -77
- package/src/models/MolliePayment.ts +7 -7
- package/src/models/MollieToken.ts +131 -126
- package/src/models/OneTimeToken.ts +40 -39
- package/src/models/Order.ts +379 -372
- package/src/models/Organization.ts +332 -325
- package/src/models/OrganizationRegistrationPeriod.ts +50 -50
- package/src/models/PasswordToken.ts +42 -42
- package/src/models/PayconiqPayment.ts +80 -76
- package/src/models/Payment.ts +86 -86
- package/src/models/Platform.ts +21 -22
- package/src/models/RegisterCode.ts +26 -26
- package/src/models/Registration.ts +167 -168
- package/src/models/RegistrationPeriod.ts +29 -29
- package/src/models/STCredit.ts +24 -25
- package/src/models/STInvoice.ts +34 -34
- package/src/models/STPackage.ts +143 -136
- package/src/models/STPendingInvoice.ts +26 -26
- package/src/models/StripeAccount.ts +27 -27
- package/src/models/StripeCheckoutSession.ts +10 -10
- package/src/models/StripePaymentIntent.ts +10 -10
- package/src/models/Ticket.ts +51 -52
- package/src/models/Token.test.ts +13 -13
- package/src/models/Token.ts +64 -63
- package/src/models/UsedRegisterCode.ts +20 -21
- package/src/models/User.ts +148 -144
- package/src/models/UserPermissions.ts +25 -28
- package/src/models/Webshop.ts +53 -53
- package/src/models/WebshopDiscountCode.ts +33 -33
- package/src/models/addresses/City.ts +12 -12
- package/src/models/addresses/PostalCode.test.ts +68 -69
- package/src/models/addresses/PostalCode.ts +57 -57
- package/src/models/addresses/Province.ts +8 -8
- package/src/models/addresses/Street.ts +10 -12
- package/src/models/index.ts +54 -55
- package/src/structures/OrganizationServerMetaData.ts +36 -36
|
@@ -1,123 +1,122 @@
|
|
|
1
|
-
import { column, Database, Model } from
|
|
1
|
+
import { column, Database, Model } from '@simonbackx/simple-database';
|
|
2
2
|
import { DecodedRequest } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
|
-
import { I18n } from
|
|
5
|
-
import { Email, EmailInterfaceRecipient } from
|
|
6
|
-
import { Address, Country, DNSRecordStatus, EmailTemplateType, OrganizationEmail, OrganizationMetaData, OrganizationPrivateMetaData, Organization as OrganizationStruct, PaymentMethod, PaymentProvider, PrivatePaymentConfiguration, Recipient, Replacement, STPackageType, TransferSettings } from
|
|
4
|
+
import { I18n } from '@stamhoofd/backend-i18n';
|
|
5
|
+
import { Email, EmailInterfaceRecipient } from '@stamhoofd/email';
|
|
6
|
+
import { Address, Country, DNSRecordStatus, EmailTemplateType, OrganizationEmail, OrganizationMetaData, OrganizationPrivateMetaData, Organization as OrganizationStruct, PaymentMethod, PaymentProvider, PrivatePaymentConfiguration, Recipient, Replacement, STPackageType, TransferSettings } from '@stamhoofd/structures';
|
|
7
7
|
import { AWSError } from 'aws-sdk';
|
|
8
8
|
import SES from 'aws-sdk/clients/sesv2';
|
|
9
9
|
import { PromiseResult } from 'aws-sdk/lib/request';
|
|
10
|
-
import { v4 as uuidv4 } from
|
|
10
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
11
11
|
|
|
12
|
-
import { QueueHandler } from
|
|
13
|
-
import { validateDNSRecords } from
|
|
14
|
-
import { getEmailBuilderForTemplate } from
|
|
12
|
+
import { QueueHandler } from '@stamhoofd/queues';
|
|
13
|
+
import { validateDNSRecords } from '../helpers/DNSValidator';
|
|
14
|
+
import { getEmailBuilderForTemplate } from '../helpers/EmailBuilder';
|
|
15
15
|
import { OrganizationServerMetaData } from '../structures/OrganizationServerMetaData';
|
|
16
|
-
import { OrganizationRegistrationPeriod, StripeAccount } from
|
|
16
|
+
import { OrganizationRegistrationPeriod, StripeAccount } from './';
|
|
17
17
|
|
|
18
18
|
export class Organization extends Model {
|
|
19
|
-
static table =
|
|
19
|
+
static table = 'organizations';
|
|
20
20
|
|
|
21
21
|
@column({
|
|
22
|
-
primary: true, type:
|
|
22
|
+
primary: true, type: 'string', beforeSave(value) {
|
|
23
23
|
return value ?? uuidv4();
|
|
24
|
-
}
|
|
24
|
+
},
|
|
25
25
|
})
|
|
26
26
|
id!: string;
|
|
27
27
|
|
|
28
|
-
@column({ type:
|
|
28
|
+
@column({ type: 'string' })
|
|
29
29
|
name: string;
|
|
30
30
|
|
|
31
31
|
/// URL to a website page or a Facebook page (including http)
|
|
32
|
-
@column({ type:
|
|
32
|
+
@column({ type: 'string', nullable: true })
|
|
33
33
|
website: string | null = null;
|
|
34
34
|
|
|
35
35
|
/// A custom domain name that is used to host the register application (should be unique)
|
|
36
36
|
// E.g. inschrijven.scoutswetteren.be
|
|
37
|
-
@column({ type:
|
|
37
|
+
@column({ type: 'string', nullable: true })
|
|
38
38
|
registerDomain: string | null = null;
|
|
39
39
|
|
|
40
40
|
// Unique representation of this organization from a string, that is used to provide the default domains
|
|
41
41
|
// in uri.stamhoofd.be
|
|
42
|
-
@column({ type:
|
|
42
|
+
@column({ type: 'string' })
|
|
43
43
|
uri: string;
|
|
44
44
|
|
|
45
|
-
@column({ type:
|
|
45
|
+
@column({ type: 'string' })
|
|
46
46
|
periodId: string;
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* Public meta data
|
|
50
50
|
*/
|
|
51
|
-
@column({ type:
|
|
51
|
+
@column({ type: 'json', decoder: OrganizationMetaData })
|
|
52
52
|
meta: OrganizationMetaData;
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Data only accessible by the owners / users with special permissions
|
|
56
56
|
*/
|
|
57
|
-
@column({ type:
|
|
58
|
-
privateMeta: OrganizationPrivateMetaData = OrganizationPrivateMetaData.create({})
|
|
57
|
+
@column({ type: 'json', decoder: OrganizationPrivateMetaData })
|
|
58
|
+
privateMeta: OrganizationPrivateMetaData = OrganizationPrivateMetaData.create({});
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Data only accessible by the server
|
|
62
62
|
*/
|
|
63
|
-
@column({ type:
|
|
64
|
-
serverMeta: OrganizationServerMetaData = OrganizationServerMetaData.create({})
|
|
63
|
+
@column({ type: 'json', decoder: OrganizationServerMetaData })
|
|
64
|
+
serverMeta: OrganizationServerMetaData = OrganizationServerMetaData.create({});
|
|
65
65
|
|
|
66
|
-
@column({ type:
|
|
66
|
+
@column({ type: 'json', decoder: Address })
|
|
67
67
|
address: Address;
|
|
68
68
|
|
|
69
69
|
@column({
|
|
70
|
-
type:
|
|
71
|
-
return this.name+
|
|
72
|
-
}
|
|
70
|
+
type: 'string', beforeSave: function (this: Organization) {
|
|
71
|
+
return this.name + '\n' + this.address.toString();
|
|
72
|
+
},
|
|
73
73
|
})
|
|
74
|
-
searchIndex: string
|
|
74
|
+
searchIndex: string;
|
|
75
75
|
|
|
76
76
|
@column({
|
|
77
|
-
type:
|
|
77
|
+
type: 'datetime', beforeSave(old?: any) {
|
|
78
78
|
if (old !== undefined) {
|
|
79
79
|
return old;
|
|
80
80
|
}
|
|
81
|
-
const date = new Date()
|
|
82
|
-
date.setMilliseconds(0)
|
|
83
|
-
return date
|
|
84
|
-
}
|
|
81
|
+
const date = new Date();
|
|
82
|
+
date.setMilliseconds(0);
|
|
83
|
+
return date;
|
|
84
|
+
},
|
|
85
85
|
})
|
|
86
|
-
createdAt: Date
|
|
86
|
+
createdAt: Date;
|
|
87
87
|
|
|
88
88
|
@column({
|
|
89
|
-
type:
|
|
90
|
-
const date = new Date()
|
|
91
|
-
date.setMilliseconds(0)
|
|
92
|
-
return date
|
|
89
|
+
type: 'datetime', beforeSave() {
|
|
90
|
+
const date = new Date();
|
|
91
|
+
date.setMilliseconds(0);
|
|
92
|
+
return date;
|
|
93
93
|
},
|
|
94
|
-
skipUpdate: true
|
|
94
|
+
skipUpdate: true,
|
|
95
95
|
})
|
|
96
|
-
updatedAt: Date
|
|
96
|
+
updatedAt: Date;
|
|
97
97
|
|
|
98
|
-
@column({type: 'boolean'})
|
|
98
|
+
@column({ type: 'boolean' })
|
|
99
99
|
active = true;
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
102
|
* Return default locale confiruation
|
|
103
103
|
*/
|
|
104
104
|
get i18n() {
|
|
105
|
-
return new I18n(
|
|
105
|
+
return new I18n('nl', this.address.country);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
109
|
* Makes sure empty name is replaced with organization name
|
|
110
110
|
*/
|
|
111
111
|
get mappedTransferSettings(): TransferSettings {
|
|
112
|
-
return this.meta.transferSettings.fillMissing(TransferSettings.create({creditor: this.name}));
|
|
112
|
+
return this.meta.transferSettings.fillMissing(TransferSettings.create({ creditor: this.name }));
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
|
|
116
115
|
// Methods
|
|
117
116
|
static async getByURI(uri: string): Promise<Organization | undefined> {
|
|
118
117
|
const [rows] = await Database.select(
|
|
119
118
|
`SELECT ${this.getDefaultSelect()} FROM ${this.table} WHERE \`uri\` = ? LIMIT 1`,
|
|
120
|
-
[uri]
|
|
119
|
+
[uri],
|
|
121
120
|
);
|
|
122
121
|
|
|
123
122
|
if (rows.length == 0) {
|
|
@@ -132,25 +131,25 @@ export class Organization extends Model {
|
|
|
132
131
|
static async getByEmail(email: string): Promise<Organization | undefined> {
|
|
133
132
|
if (email.startsWith('noreply-')) {
|
|
134
133
|
// Trim
|
|
135
|
-
email = email.substring(
|
|
134
|
+
email = email.substring('noreply-'.length);
|
|
136
135
|
}
|
|
137
|
-
|
|
136
|
+
|
|
138
137
|
for (const domain of [
|
|
139
138
|
...Object.values(STAMHOOFD.domains.defaultBroadcastEmail ?? {}),
|
|
140
139
|
...Object.values(STAMHOOFD.domains.defaultTransactionalEmail ?? {}),
|
|
141
140
|
]) {
|
|
142
|
-
if (email.endsWith(
|
|
143
|
-
const uri = email.substring(0, email.length - (
|
|
144
|
-
return await Organization.getByURI(uri)
|
|
141
|
+
if (email.endsWith('@' + domain)) {
|
|
142
|
+
const uri = email.substring(0, email.length - ('@' + domain).length);
|
|
143
|
+
return await Organization.getByURI(uri);
|
|
145
144
|
}
|
|
146
145
|
}
|
|
147
146
|
|
|
148
|
-
const at = email.indexOf(
|
|
149
|
-
const domain = email.substring(at+1)
|
|
147
|
+
const at = email.indexOf('@');
|
|
148
|
+
const domain = email.substring(at + 1);
|
|
150
149
|
|
|
151
150
|
const [rows] = await Database.select(
|
|
152
151
|
`SELECT ${this.getDefaultSelect()} FROM ${this.table} WHERE privateMeta->"$.value.mailDomain" = ? LIMIT 1`,
|
|
153
|
-
[domain]
|
|
152
|
+
[domain],
|
|
154
153
|
);
|
|
155
154
|
|
|
156
155
|
if (rows.length == 0) {
|
|
@@ -161,13 +160,11 @@ export class Organization extends Model {
|
|
|
161
160
|
return this.fromRow(rows[0][this.table]);
|
|
162
161
|
}
|
|
163
162
|
|
|
164
|
-
|
|
165
|
-
|
|
166
163
|
// Methods
|
|
167
164
|
static async getByRegisterDomain(host: string): Promise<Organization | undefined> {
|
|
168
165
|
const [rows] = await Database.select(
|
|
169
166
|
`SELECT ${this.getDefaultSelect()} FROM ${this.table} WHERE \`registerDomain\` = ? LIMIT 1`,
|
|
170
|
-
[host]
|
|
167
|
+
[host],
|
|
171
168
|
);
|
|
172
169
|
|
|
173
170
|
if (rows.length == 0) {
|
|
@@ -186,38 +183,38 @@ export class Organization extends Model {
|
|
|
186
183
|
static async getFromRequest(request: DecodedRequest<any, any, any>): Promise<Organization> {
|
|
187
184
|
const organization = await Organization.fromApiHost(request.host);
|
|
188
185
|
|
|
189
|
-
const i18n = I18n.fromRequest(request)
|
|
190
|
-
i18n.switchToLocale({ country: organization.address.country })
|
|
186
|
+
const i18n = I18n.fromRequest(request);
|
|
187
|
+
i18n.switchToLocale({ country: organization.address.country });
|
|
191
188
|
|
|
192
|
-
return organization
|
|
189
|
+
return organization;
|
|
193
190
|
}
|
|
194
191
|
|
|
195
192
|
/**
|
|
196
193
|
* Get an Organization by looking at the host of a request
|
|
197
194
|
* Format is 2331c59a-0cbe-4279-871c-ea9d0474cd54.api.stamhoofd.app
|
|
198
195
|
*/
|
|
199
|
-
static async fromApiHost(host: string, options?: {allowInactive?: boolean}): Promise<Organization> {
|
|
200
|
-
const splitted = host.split('.')
|
|
196
|
+
static async fromApiHost(host: string, options?: { allowInactive?: boolean }): Promise<Organization> {
|
|
197
|
+
const splitted = host.split('.');
|
|
201
198
|
if (splitted.length < 2) {
|
|
202
199
|
throw new SimpleError({
|
|
203
|
-
code:
|
|
204
|
-
message:
|
|
200
|
+
code: 'invalid_host',
|
|
201
|
+
message: 'Please specify the organization in the hostname',
|
|
205
202
|
});
|
|
206
203
|
}
|
|
207
|
-
const id = splitted[0]
|
|
204
|
+
const id = splitted[0];
|
|
208
205
|
const organization = await this.getByID(id);
|
|
209
206
|
if (!organization) {
|
|
210
207
|
throw new SimpleError({
|
|
211
|
-
code:
|
|
212
|
-
message:
|
|
208
|
+
code: 'invalid_organization',
|
|
209
|
+
message: 'No organization known for host ' + host,
|
|
213
210
|
});
|
|
214
211
|
}
|
|
215
212
|
|
|
216
213
|
if (!organization.active && !options?.allowInactive) {
|
|
217
214
|
throw new SimpleError({
|
|
218
|
-
code:
|
|
219
|
-
message:
|
|
220
|
-
human: 'Deze groep is gearchiveerd'
|
|
215
|
+
code: 'archived',
|
|
216
|
+
message: 'This organization is archived',
|
|
217
|
+
human: 'Deze groep is gearchiveerd',
|
|
221
218
|
});
|
|
222
219
|
}
|
|
223
220
|
return organization;
|
|
@@ -230,73 +227,74 @@ export class Organization extends Model {
|
|
|
230
227
|
if (this.registerDomain) {
|
|
231
228
|
let d = this.registerDomain;
|
|
232
229
|
|
|
233
|
-
if (i18n && i18n.language
|
|
234
|
-
d +=
|
|
230
|
+
if (i18n && i18n.language !== this.i18n.language) {
|
|
231
|
+
d += '/' + i18n.language;
|
|
235
232
|
}
|
|
236
233
|
|
|
237
234
|
return d;
|
|
238
235
|
}
|
|
239
|
-
return this.getDefaultHost(i18n)
|
|
236
|
+
return this.getDefaultHost(i18n);
|
|
240
237
|
}
|
|
241
238
|
|
|
242
239
|
getDefaultHost(i18n?: I18n): string {
|
|
243
240
|
if (!STAMHOOFD.domains.registration) {
|
|
244
241
|
return STAMHOOFD.domains.dashboard + '/' + (i18n?.locale ?? this.i18n.locale) + '/leden/' + this.uri;
|
|
245
242
|
}
|
|
246
|
-
let defaultDomain = STAMHOOFD.domains.registration[this.address.country] ?? STAMHOOFD.domains.registration[
|
|
243
|
+
let defaultDomain = STAMHOOFD.domains.registration[this.address.country] ?? STAMHOOFD.domains.registration[''];
|
|
247
244
|
|
|
248
|
-
if (i18n && i18n.language
|
|
249
|
-
defaultDomain +=
|
|
245
|
+
if (i18n && i18n.language !== this.i18n.language) {
|
|
246
|
+
defaultDomain += '/' + i18n.language;
|
|
250
247
|
}
|
|
251
248
|
|
|
252
|
-
return this.uri +
|
|
249
|
+
return this.uri + '.' + defaultDomain;
|
|
253
250
|
}
|
|
254
251
|
|
|
255
252
|
get marketingDomain(): string {
|
|
256
|
-
return STAMHOOFD.domains.marketing[this.address.country] ?? STAMHOOFD.domains.marketing[
|
|
253
|
+
return STAMHOOFD.domains.marketing[this.address.country] ?? STAMHOOFD.domains.marketing[''];
|
|
257
254
|
}
|
|
258
255
|
|
|
259
256
|
getApiHost(): string {
|
|
260
257
|
const defaultDomain = STAMHOOFD.domains.api;
|
|
261
258
|
if (!defaultDomain) {
|
|
262
|
-
throw new Error(
|
|
259
|
+
throw new Error('Missing hostname in environment');
|
|
263
260
|
}
|
|
264
|
-
return this.id+
|
|
261
|
+
return this.id + '.' + defaultDomain;
|
|
265
262
|
}
|
|
266
263
|
|
|
267
|
-
private _cachedPeriod?: OrganizationRegistrationPeriod
|
|
264
|
+
private _cachedPeriod?: OrganizationRegistrationPeriod;
|
|
268
265
|
|
|
269
266
|
async getPeriod() {
|
|
270
267
|
if (this._cachedPeriod) {
|
|
271
268
|
return this._cachedPeriod;
|
|
272
269
|
}
|
|
273
270
|
|
|
274
|
-
const oPeriods = await OrganizationRegistrationPeriod.where({ periodId: this.periodId, organizationId: this.id }, {limit: 1})
|
|
275
|
-
|
|
271
|
+
const oPeriods = await OrganizationRegistrationPeriod.where({ periodId: this.periodId, organizationId: this.id }, { limit: 1 });
|
|
272
|
+
|
|
276
273
|
let oPeriod: OrganizationRegistrationPeriod;
|
|
277
274
|
if (oPeriods.length == 0) {
|
|
278
275
|
// Automatically create a period
|
|
279
276
|
oPeriod = await QueueHandler.schedule('create-missing-organization-period', async () => {
|
|
280
277
|
// Race condition check
|
|
281
|
-
const updatedPeriods =
|
|
278
|
+
const updatedPeriods = await OrganizationRegistrationPeriod.where({ periodId: this.periodId, organizationId: this.id }, { limit: 1 });
|
|
282
279
|
|
|
283
280
|
if (updatedPeriods.length) {
|
|
284
|
-
return updatedPeriods[0]
|
|
281
|
+
return updatedPeriods[0];
|
|
285
282
|
}
|
|
286
283
|
|
|
287
|
-
console.log('Automatically creating new organization registration period for organization ' + this.id + ' and period ' + this.periodId + ' - organization period is missing')
|
|
288
|
-
const created = new OrganizationRegistrationPeriod()
|
|
289
|
-
created.organizationId = this.id
|
|
290
|
-
created.periodId = this.periodId
|
|
291
|
-
await created.save()
|
|
292
|
-
return created
|
|
293
|
-
})
|
|
294
|
-
}
|
|
284
|
+
console.log('Automatically creating new organization registration period for organization ' + this.id + ' and period ' + this.periodId + ' - organization period is missing');
|
|
285
|
+
const created = new OrganizationRegistrationPeriod();
|
|
286
|
+
created.organizationId = this.id;
|
|
287
|
+
created.periodId = this.periodId;
|
|
288
|
+
await created.save();
|
|
289
|
+
return created;
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
295
293
|
oPeriod = oPeriods[0];
|
|
296
294
|
}
|
|
297
295
|
|
|
298
|
-
this._cachedPeriod = oPeriod
|
|
299
|
-
return oPeriod
|
|
296
|
+
this._cachedPeriod = oPeriod;
|
|
297
|
+
return oPeriod;
|
|
300
298
|
}
|
|
301
299
|
|
|
302
300
|
getBaseStructure(): OrganizationStruct {
|
|
@@ -310,147 +308,151 @@ export class Organization extends Model {
|
|
|
310
308
|
uri: this.uri,
|
|
311
309
|
website: this.website,
|
|
312
310
|
createdAt: this.createdAt,
|
|
313
|
-
})
|
|
311
|
+
});
|
|
314
312
|
}
|
|
315
313
|
|
|
316
314
|
async updateDNSRecords() {
|
|
317
315
|
const organization = this;
|
|
318
316
|
|
|
319
317
|
// Check initial status
|
|
320
|
-
let isValidRecords = true
|
|
318
|
+
let isValidRecords = true;
|
|
321
319
|
for (const record of organization.privateMeta.dnsRecords) {
|
|
322
|
-
if (record.status
|
|
323
|
-
isValidRecords = false
|
|
320
|
+
if (record.status !== DNSRecordStatus.Valid) {
|
|
321
|
+
isValidRecords = false;
|
|
324
322
|
}
|
|
325
323
|
}
|
|
326
|
-
|
|
327
|
-
const { allValid } = await validateDNSRecords(organization.privateMeta.dnsRecords)
|
|
328
324
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
const
|
|
325
|
+
const { allValid } = await validateDNSRecords(organization.privateMeta.dnsRecords);
|
|
326
|
+
|
|
327
|
+
if (organization.registerDomain ?? organization.privateMeta.pendingRegisterDomain) {
|
|
328
|
+
const registerDomainRecord = (organization.privateMeta.pendingRegisterDomain ?? organization.registerDomain) + '.';
|
|
329
|
+
const records = organization.privateMeta.dnsRecords.filter(r => r.name === registerDomainRecord);
|
|
330
|
+
const areRegisterDomainRecordsValid = records.length === 0 || records.every(r => r.status === DNSRecordStatus.Valid);
|
|
333
331
|
|
|
334
332
|
if (areRegisterDomainRecordsValid) {
|
|
335
333
|
// We can setup the register domain if needed
|
|
336
334
|
if (organization.privateMeta.pendingRegisterDomain !== null) {
|
|
337
|
-
organization.registerDomain = organization.privateMeta.pendingRegisterDomain
|
|
335
|
+
organization.registerDomain = organization.privateMeta.pendingRegisterDomain;
|
|
338
336
|
organization.privateMeta.pendingRegisterDomain = null;
|
|
339
337
|
|
|
340
|
-
console.log(
|
|
338
|
+
console.log('Did set register domain for ' + this.id + ' to ' + organization.registerDomain);
|
|
341
339
|
}
|
|
342
|
-
}
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
343
342
|
// Clear register domain
|
|
344
343
|
if (organization.registerDomain) {
|
|
345
344
|
// We need to clear it, to prevent sending e-mails with invalid links
|
|
346
|
-
organization.privateMeta.pendingRegisterDomain = organization.privateMeta.pendingRegisterDomain ?? organization.registerDomain
|
|
347
|
-
organization.registerDomain = null
|
|
345
|
+
organization.privateMeta.pendingRegisterDomain = organization.privateMeta.pendingRegisterDomain ?? organization.registerDomain;
|
|
346
|
+
organization.registerDomain = null;
|
|
348
347
|
|
|
349
|
-
console.log(
|
|
348
|
+
console.log('Cleared register domain for ' + this.id + ' because of invalid non txt records');
|
|
350
349
|
}
|
|
351
350
|
}
|
|
352
351
|
}
|
|
353
352
|
|
|
354
353
|
if (allValid) {
|
|
355
354
|
if (organization.privateMeta.pendingMailDomain !== null) {
|
|
356
|
-
organization.privateMeta.mailDomain = organization.privateMeta.pendingMailDomain
|
|
355
|
+
organization.privateMeta.mailDomain = organization.privateMeta.pendingMailDomain;
|
|
357
356
|
organization.privateMeta.pendingMailDomain = null;
|
|
358
357
|
}
|
|
359
358
|
|
|
360
|
-
const wasUnstable = organization.serverMeta.isDNSUnstable
|
|
361
|
-
organization.serverMeta.markDNSValid()
|
|
359
|
+
const wasUnstable = organization.serverMeta.isDNSUnstable;
|
|
360
|
+
organization.serverMeta.markDNSValid();
|
|
362
361
|
|
|
363
|
-
const didSendDomainSetupMail = organization.serverMeta.didSendDomainSetupMail
|
|
364
|
-
const didSendWarning = organization.serverMeta.DNSRecordWarningCount > 0
|
|
365
|
-
organization.serverMeta.DNSRecordWarningCount = 0
|
|
362
|
+
const didSendDomainSetupMail = organization.serverMeta.didSendDomainSetupMail;
|
|
363
|
+
const didSendWarning = organization.serverMeta.DNSRecordWarningCount > 0;
|
|
364
|
+
organization.serverMeta.DNSRecordWarningCount = 0;
|
|
366
365
|
|
|
367
|
-
const wasActive = this.privateMeta.mailDomainActive
|
|
368
|
-
await this.updateAWSMailIdenitity()
|
|
366
|
+
const wasActive = this.privateMeta.mailDomainActive;
|
|
367
|
+
await this.updateAWSMailIdenitity();
|
|
369
368
|
|
|
370
369
|
// yay! Do not Save until after doing AWS changes
|
|
371
|
-
await organization.save()
|
|
370
|
+
await organization.save();
|
|
372
371
|
|
|
373
372
|
if (wasUnstable && !organization.serverMeta.isDNSUnstable) {
|
|
374
|
-
console.warn('DNS settings became stable for ' + this.name + ' '+this.id)
|
|
373
|
+
console.warn('DNS settings became stable for ' + this.name + ' ' + this.id);
|
|
375
374
|
|
|
376
375
|
await this.sendEmailTemplate({
|
|
377
376
|
type: EmailTemplateType.OrganizationStableDNS,
|
|
378
|
-
bcc: true
|
|
379
|
-
})
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
organization.serverMeta.didSendDomainSetupMail = true
|
|
383
|
-
await organization.save()
|
|
377
|
+
bcc: true,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
else if (!wasActive && this.privateMeta.mailDomainActive && (!didSendDomainSetupMail || didSendWarning) && !organization.serverMeta.isDNSUnstable) {
|
|
381
|
+
organization.serverMeta.didSendDomainSetupMail = true;
|
|
382
|
+
await organization.save();
|
|
384
383
|
|
|
385
384
|
if (!didSendDomainSetupMail) {
|
|
386
385
|
await this.sendEmailTemplate({
|
|
387
|
-
type: EmailTemplateType.OrganizationDNSSetupComplete
|
|
388
|
-
})
|
|
389
|
-
}
|
|
386
|
+
type: EmailTemplateType.OrganizationDNSSetupComplete,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
390
|
await this.sendEmailTemplate({
|
|
391
|
-
type: EmailTemplateType.OrganizationValidDNS
|
|
392
|
-
})
|
|
391
|
+
type: EmailTemplateType.OrganizationValidDNS,
|
|
392
|
+
});
|
|
393
393
|
}
|
|
394
394
|
}
|
|
395
|
-
}
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
396
397
|
// DNS settings gone broken
|
|
397
398
|
if (organization.privateMeta.mailDomain) {
|
|
398
|
-
organization.privateMeta.pendingMailDomain = organization.privateMeta.pendingMailDomain ?? organization.privateMeta.mailDomain
|
|
399
|
-
organization.privateMeta.mailDomain = null
|
|
399
|
+
organization.privateMeta.pendingMailDomain = organization.privateMeta.pendingMailDomain ?? organization.privateMeta.mailDomain;
|
|
400
|
+
organization.privateMeta.mailDomain = null;
|
|
400
401
|
}
|
|
401
402
|
|
|
402
|
-
const wasDNSUnstable = organization.serverMeta.isDNSUnstable
|
|
403
|
+
const wasDNSUnstable = organization.serverMeta.isDNSUnstable;
|
|
403
404
|
|
|
404
|
-
organization.serverMeta.markDNSFailure()
|
|
405
|
+
organization.serverMeta.markDNSFailure();
|
|
405
406
|
|
|
406
407
|
// disable AWS emails
|
|
407
|
-
this.privateMeta.mailDomainActive = false
|
|
408
|
+
this.privateMeta.mailDomainActive = false;
|
|
408
409
|
|
|
409
410
|
// save
|
|
410
|
-
await organization.save()
|
|
411
|
+
await organization.save();
|
|
411
412
|
|
|
412
413
|
if (!wasDNSUnstable && organization.serverMeta.isDNSUnstable) {
|
|
413
414
|
// DNS became instable
|
|
414
|
-
console.warn('DNS settings became instable for ' + this.name + ' '+this.id)
|
|
415
|
+
console.warn('DNS settings became instable for ' + this.name + ' ' + this.id);
|
|
415
416
|
|
|
416
417
|
await this.sendEmailTemplate({
|
|
417
418
|
type: EmailTemplateType.OrganizationUnstableDNS,
|
|
418
|
-
bcc: true
|
|
419
|
-
})
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
|
|
419
|
+
bcc: true,
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
else if (!organization.serverMeta.isDNSUnstable && organization.serverMeta.didSendDomainSetupMail && organization.serverMeta.DNSRecordWarningCount == 0) {
|
|
423
|
+
organization.serverMeta.DNSRecordWarningCount += 1;
|
|
424
|
+
await organization.save();
|
|
423
425
|
|
|
424
426
|
await this.sendEmailTemplate({
|
|
425
|
-
type: EmailTemplateType.OrganizationInvalidDNS
|
|
426
|
-
})
|
|
427
|
+
type: EmailTemplateType.OrganizationInvalidDNS,
|
|
428
|
+
});
|
|
427
429
|
}
|
|
428
430
|
}
|
|
429
431
|
}
|
|
430
432
|
|
|
431
433
|
async sendEmailTemplate(data: {
|
|
432
|
-
type: EmailTemplateType
|
|
433
|
-
personal?: boolean
|
|
434
|
-
replyTo?: string
|
|
435
|
-
bcc?: boolean
|
|
434
|
+
type: EmailTemplateType;
|
|
435
|
+
personal?: boolean;
|
|
436
|
+
replyTo?: string;
|
|
437
|
+
bcc?: boolean;
|
|
436
438
|
}) {
|
|
437
439
|
const recipients = await this.getAdminRecipients();
|
|
438
|
-
const defaultI18n = new I18n(
|
|
440
|
+
const defaultI18n = new I18n('nl', Country.Belgium);
|
|
439
441
|
const i18n = this.i18n;
|
|
440
442
|
|
|
441
443
|
const replaceAll = [
|
|
442
444
|
{
|
|
443
445
|
from: defaultI18n.localizedDomains.marketing(),
|
|
444
|
-
to: i18n.localizedDomains.marketing()
|
|
446
|
+
to: i18n.localizedDomains.marketing(),
|
|
445
447
|
},
|
|
446
448
|
{
|
|
447
|
-
from: defaultI18n.$t(
|
|
448
|
-
to: i18n.$t(
|
|
449
|
+
from: defaultI18n.$t('59b85264-c4c3-4cf6-8923-9b43282b2787'),
|
|
450
|
+
to: i18n.$t('59b85264-c4c3-4cf6-8923-9b43282b2787'),
|
|
449
451
|
},
|
|
450
452
|
{
|
|
451
|
-
from: defaultI18n.$t(
|
|
452
|
-
to: i18n.$t(
|
|
453
|
-
}
|
|
453
|
+
from: defaultI18n.$t('6b3555a2-ace4-4f37-a1fd-18921552f2b5'),
|
|
454
|
+
to: i18n.$t('6b3555a2-ace4-4f37-a1fd-18921552f2b5'),
|
|
455
|
+
},
|
|
454
456
|
];
|
|
455
457
|
|
|
456
458
|
// Create e-mail builder
|
|
@@ -458,7 +460,7 @@ export class Organization extends Model {
|
|
|
458
460
|
replaceAll,
|
|
459
461
|
recipients,
|
|
460
462
|
template: {
|
|
461
|
-
type: data.type
|
|
463
|
+
type: data.type,
|
|
462
464
|
},
|
|
463
465
|
from: data.personal ? Email.getPersonalEmailFor(this.i18n) : Email.getInternalEmailFor(this.i18n),
|
|
464
466
|
singleBcc: data.bcc ? 'simon@stamhoofd.be' : undefined,
|
|
@@ -467,26 +469,25 @@ export class Organization extends Model {
|
|
|
467
469
|
defaultReplacements: [
|
|
468
470
|
Replacement.create({
|
|
469
471
|
token: 'mailDomain',
|
|
470
|
-
value: this.privateMeta.mailDomain ?? this.privateMeta.pendingMailDomain ?? ''
|
|
471
|
-
})
|
|
472
|
+
value: this.privateMeta.mailDomain ?? this.privateMeta.pendingMailDomain ?? '',
|
|
473
|
+
}),
|
|
472
474
|
],
|
|
473
475
|
unsubscribeType: 'marketing',
|
|
474
|
-
fromStamhoofd: true
|
|
475
|
-
})
|
|
476
|
+
fromStamhoofd: true,
|
|
477
|
+
});
|
|
476
478
|
|
|
477
479
|
if (builder) {
|
|
478
|
-
Email.schedule(builder)
|
|
480
|
+
Email.schedule(builder);
|
|
479
481
|
}
|
|
480
482
|
}
|
|
481
483
|
|
|
482
484
|
async deleteAWSMailIdenitity(mailDomain: string) {
|
|
483
|
-
|
|
484
485
|
// Protect specific domain names
|
|
485
|
-
if ([
|
|
486
|
-
return
|
|
486
|
+
if (['stamhoofd.be', 'stamhoofd.nl', 'stamhoofd.shop', 'stamhoofd.app', 'stamhoofd.email'].includes(mailDomain)) {
|
|
487
|
+
return;
|
|
487
488
|
}
|
|
488
489
|
|
|
489
|
-
if (STAMHOOFD.environment
|
|
490
|
+
if (STAMHOOFD.environment !== 'production') {
|
|
490
491
|
// Temporary ignore this
|
|
491
492
|
return;
|
|
492
493
|
}
|
|
@@ -494,30 +495,30 @@ export class Organization extends Model {
|
|
|
494
495
|
const sesv2 = new SES();
|
|
495
496
|
|
|
496
497
|
// Check if mail identitiy already exists..
|
|
497
|
-
let exists = false
|
|
498
|
-
let existing: PromiseResult<SES.GetEmailIdentityResponse, AWSError> | undefined = undefined
|
|
498
|
+
let exists = false;
|
|
499
|
+
let existing: PromiseResult<SES.GetEmailIdentityResponse, AWSError> | undefined = undefined;
|
|
499
500
|
try {
|
|
500
501
|
existing = await sesv2.getEmailIdentity({
|
|
501
|
-
EmailIdentity: mailDomain
|
|
502
|
-
}).promise()
|
|
503
|
-
exists = true
|
|
502
|
+
EmailIdentity: mailDomain,
|
|
503
|
+
}).promise();
|
|
504
|
+
exists = true;
|
|
504
505
|
|
|
505
506
|
// Check if DKIM keys are the same
|
|
506
507
|
if (existing.VerifiedForSendingStatus === true) {
|
|
507
|
-
console.log(
|
|
508
|
-
return
|
|
508
|
+
console.log('Cant delete AWS mail idenitiy @' + this.id + ' for ' + mailDomain + ': already validated and might be in use by other organizations');
|
|
509
|
+
return;
|
|
509
510
|
}
|
|
510
511
|
|
|
511
|
-
console.log(
|
|
512
|
+
console.log('Deleting AWS mail idenitiy @' + this.id + ' for ' + mailDomain);
|
|
512
513
|
|
|
513
514
|
await sesv2.deleteEmailIdentity({
|
|
514
|
-
EmailIdentity: mailDomain
|
|
515
|
-
}).promise()
|
|
516
|
-
console.log(
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
console.error(
|
|
520
|
-
console.error(e)
|
|
515
|
+
EmailIdentity: mailDomain,
|
|
516
|
+
}).promise();
|
|
517
|
+
console.log('Deleted AWS mail idenitiy @' + this.id + ' for ' + this.privateMeta.mailDomain);
|
|
518
|
+
}
|
|
519
|
+
catch (e) {
|
|
520
|
+
console.error('Could not delete AWS email identitiy @' + this.id + ' for ' + this.privateMeta.mailDomain);
|
|
521
|
+
console.error(e);
|
|
521
522
|
}
|
|
522
523
|
}
|
|
523
524
|
|
|
@@ -530,13 +531,13 @@ export class Organization extends Model {
|
|
|
530
531
|
}
|
|
531
532
|
|
|
532
533
|
// Protect specific domain names
|
|
533
|
-
if ([
|
|
534
|
-
console.error(
|
|
534
|
+
if (['stamhoofd.be', 'stamhoofd.nl', 'stamhoofd.shop', 'stamhoofd.app', 'stamhoofd.email'].includes(this.privateMeta.mailDomain)) {
|
|
535
|
+
console.error('Tried to validate AWS mail identity with protected domains @' + this.id);
|
|
535
536
|
this.privateMeta.mailDomainActive = false;
|
|
536
|
-
return
|
|
537
|
+
return;
|
|
537
538
|
}
|
|
538
539
|
|
|
539
|
-
if (STAMHOOFD.environment
|
|
540
|
+
if (STAMHOOFD.environment !== 'production') {
|
|
540
541
|
// Temporary ignore this
|
|
541
542
|
this.privateMeta.mailDomainActive = true;
|
|
542
543
|
return;
|
|
@@ -545,80 +546,81 @@ export class Organization extends Model {
|
|
|
545
546
|
const sesv2 = new SES();
|
|
546
547
|
|
|
547
548
|
// Check if mail identitiy already exists..
|
|
548
|
-
let exists = false
|
|
549
|
-
let existing: PromiseResult<SES.GetEmailIdentityResponse, AWSError> | undefined = undefined
|
|
549
|
+
let exists = false;
|
|
550
|
+
let existing: PromiseResult<SES.GetEmailIdentityResponse, AWSError> | undefined = undefined;
|
|
550
551
|
try {
|
|
551
552
|
existing = await sesv2.getEmailIdentity({
|
|
552
|
-
EmailIdentity: this.privateMeta.mailDomain
|
|
553
|
-
}).promise()
|
|
554
|
-
exists = true
|
|
553
|
+
EmailIdentity: this.privateMeta.mailDomain,
|
|
554
|
+
}).promise();
|
|
555
|
+
exists = true;
|
|
555
556
|
|
|
556
|
-
console.log(
|
|
557
|
+
console.log('AWS mail idenitiy exists already: just checking the verification status in AWS @' + this.id);
|
|
557
558
|
|
|
558
|
-
if (existing.ConfigurationSetName !==
|
|
559
|
+
if (existing.ConfigurationSetName !== 'stamhoofd-domains') {
|
|
559
560
|
// Not allowed to use this identity
|
|
560
561
|
this.privateMeta.mailDomainActive = false;
|
|
561
|
-
console.error(
|
|
562
|
+
console.error('Organization is not allowed to use email identity ' + this.privateMeta.mailDomain + ' @' + this.id + ', got ' + existing.ConfigurationSetName);
|
|
562
563
|
return;
|
|
563
564
|
}
|
|
564
565
|
|
|
565
|
-
this.privateMeta.mailDomainActive = existing.VerifiedForSendingStatus ?? false
|
|
566
|
+
this.privateMeta.mailDomainActive = existing.VerifiedForSendingStatus ?? false;
|
|
566
567
|
|
|
567
568
|
if (existing.VerifiedForSendingStatus !== true) {
|
|
568
|
-
console.error(
|
|
569
|
+
console.error('Not validated @' + this.id);
|
|
569
570
|
}
|
|
570
|
-
|
|
571
|
-
if (existing.VerifiedForSendingStatus !== true && existing.DkimAttributes?.Status ===
|
|
572
|
-
console.error(
|
|
571
|
+
|
|
572
|
+
if (existing.VerifiedForSendingStatus !== true && existing.DkimAttributes?.Status === 'FAILED') {
|
|
573
|
+
console.error('AWS failed to verify DKIM records. Triggering a forced recheck @' + this.id);
|
|
573
574
|
await sesv2.deleteEmailIdentity({
|
|
574
|
-
EmailIdentity: this.privateMeta.mailDomain
|
|
575
|
-
}).promise()
|
|
575
|
+
EmailIdentity: this.privateMeta.mailDomain,
|
|
576
|
+
}).promise();
|
|
576
577
|
|
|
577
578
|
// Recreate it immediately
|
|
578
|
-
exists = false
|
|
579
|
+
exists = false;
|
|
579
580
|
}
|
|
580
|
-
}
|
|
581
|
-
|
|
581
|
+
}
|
|
582
|
+
catch (e) {
|
|
583
|
+
console.error(e);
|
|
582
584
|
}
|
|
583
585
|
|
|
584
586
|
if (!exists) {
|
|
585
|
-
console.log(
|
|
587
|
+
console.log('Creating email identity in AWS SES...');
|
|
586
588
|
|
|
587
589
|
const result = await sesv2.createEmailIdentity({
|
|
588
590
|
EmailIdentity: this.privateMeta.mailDomain,
|
|
589
|
-
ConfigurationSetName:
|
|
591
|
+
ConfigurationSetName: 'stamhoofd-domains',
|
|
590
592
|
DkimSigningAttributes: {
|
|
591
593
|
DomainSigningPrivateKey: this.serverMeta.privateDKIMKey!,
|
|
592
|
-
DomainSigningSelector:
|
|
594
|
+
DomainSigningSelector: 'stamhoofd',
|
|
593
595
|
},
|
|
594
596
|
Tags: [
|
|
595
597
|
{
|
|
596
|
-
|
|
597
|
-
|
|
598
|
+
Key: 'OrganizationId',
|
|
599
|
+
Value: this.id,
|
|
598
600
|
},
|
|
599
601
|
{
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
}
|
|
603
|
-
]
|
|
602
|
+
Key: 'Environment',
|
|
603
|
+
Value: STAMHOOFD.environment ?? 'Unknown',
|
|
604
|
+
},
|
|
605
|
+
],
|
|
604
606
|
|
|
605
|
-
}).promise()
|
|
606
|
-
this.privateMeta.mailDomainActive = result.VerifiedForSendingStatus ?? false
|
|
607
|
+
}).promise();
|
|
608
|
+
this.privateMeta.mailDomainActive = result.VerifiedForSendingStatus ?? false;
|
|
607
609
|
|
|
608
610
|
// Disable email forwarding of bounces and complaints
|
|
609
611
|
// We handle this now with the configuration set
|
|
610
612
|
await sesv2.putEmailIdentityFeedbackAttributes({
|
|
611
613
|
EmailIdentity: this.privateMeta.mailDomain,
|
|
612
|
-
EmailForwardingEnabled: false
|
|
613
|
-
}).promise()
|
|
614
|
+
EmailForwardingEnabled: false,
|
|
615
|
+
}).promise();
|
|
614
616
|
}
|
|
615
617
|
|
|
616
618
|
if (this.privateMeta.mailFromDomain && (!exists || (existing && (!existing.MailFromAttributes || existing.MailFromAttributes.MailFromDomain !== this.privateMeta.mailFromDomain)))) {
|
|
617
619
|
// Also set a from domain, to fix SPF
|
|
618
|
-
console.log(
|
|
620
|
+
console.log('Setting mail from domain: ' + this.privateMeta.mailFromDomain + ' for ' + this.id);
|
|
619
621
|
const params = {
|
|
620
622
|
EmailIdentity: this.privateMeta.mailDomain,
|
|
621
|
-
BehaviorOnMxFailure:
|
|
623
|
+
BehaviorOnMxFailure: 'USE_DEFAULT_VALUE',
|
|
622
624
|
MailFromDomain: this.privateMeta.mailFromDomain,
|
|
623
625
|
};
|
|
624
626
|
await sesv2.putEmailIdentityMailFromAttributes(params).promise();
|
|
@@ -626,15 +628,15 @@ export class Organization extends Model {
|
|
|
626
628
|
}
|
|
627
629
|
|
|
628
630
|
async checkDrips() {
|
|
629
|
-
const days7 = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
|
|
631
|
+
const days7 = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
|
|
630
632
|
|
|
631
633
|
// Welcome drip
|
|
632
634
|
// Created maximum 7 days ago
|
|
633
635
|
if (this.createdAt > days7 && !this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripWelcome)) {
|
|
634
636
|
await this.sendEmailTemplate({
|
|
635
637
|
type: EmailTemplateType.OrganizationDripWelcome,
|
|
636
|
-
personal: true
|
|
637
|
-
})
|
|
638
|
+
personal: true,
|
|
639
|
+
});
|
|
638
640
|
|
|
639
641
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWelcome);
|
|
640
642
|
await this.save();
|
|
@@ -645,13 +647,13 @@ export class Organization extends Model {
|
|
|
645
647
|
// Webshop trial checkin
|
|
646
648
|
if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripWebshopTrialCheckin)) {
|
|
647
649
|
if (this.meta.packages.isWebshopsTrial) {
|
|
648
|
-
const activeTime = this.meta.packages.getActiveTime(STPackageType.TrialWebshops)
|
|
650
|
+
const activeTime = this.meta.packages.getActiveTime(STPackageType.TrialWebshops);
|
|
649
651
|
if (activeTime !== null && activeTime > 4 * 24 * 60 * 60 * 1000) {
|
|
650
652
|
// 7 days checkin
|
|
651
653
|
await this.sendEmailTemplate({
|
|
652
654
|
type: EmailTemplateType.OrganizationDripWebshopTrialCheckin,
|
|
653
|
-
personal: true
|
|
654
|
-
})
|
|
655
|
+
personal: true,
|
|
656
|
+
});
|
|
655
657
|
|
|
656
658
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWebshopTrialCheckin);
|
|
657
659
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripMembersTrialCheckin); // also mark members checkin
|
|
@@ -665,13 +667,13 @@ export class Organization extends Model {
|
|
|
665
667
|
// Members trial checkin
|
|
666
668
|
if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripMembersTrialCheckin)) {
|
|
667
669
|
if (this.meta.packages.isMembersTrial) {
|
|
668
|
-
const activeTime = this.meta.packages.getActiveTime(STPackageType.TrialMembers)
|
|
670
|
+
const activeTime = this.meta.packages.getActiveTime(STPackageType.TrialMembers);
|
|
669
671
|
if (activeTime !== null && activeTime > 4 * 24 * 60 * 60 * 1000) {
|
|
670
672
|
// 7 days checkin
|
|
671
673
|
await this.sendEmailTemplate({
|
|
672
674
|
type: EmailTemplateType.OrganizationDripMembersTrialCheckin,
|
|
673
|
-
personal: true
|
|
674
|
-
})
|
|
675
|
+
personal: true,
|
|
676
|
+
});
|
|
675
677
|
|
|
676
678
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripMembersTrialCheckin);
|
|
677
679
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWebshopTrialCheckin); // Also mark webshop trial checkin
|
|
@@ -685,12 +687,12 @@ export class Organization extends Model {
|
|
|
685
687
|
// Webshop trial expired after 1 week
|
|
686
688
|
if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripWebshopTrialExpired)) {
|
|
687
689
|
if (!this.meta.packages.useWebshops) {
|
|
688
|
-
const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.TrialWebshops)
|
|
690
|
+
const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.TrialWebshops);
|
|
689
691
|
if (deactivatedTime !== null && deactivatedTime < 14 * 24 * 60 * 60 * 1000 && deactivatedTime > 7 * 24 * 60 * 60 * 1000) {
|
|
690
692
|
await this.sendEmailTemplate({
|
|
691
693
|
type: EmailTemplateType.OrganizationDripWebshopTrialExpired,
|
|
692
|
-
personal: true
|
|
693
|
-
})
|
|
694
|
+
personal: true,
|
|
695
|
+
});
|
|
694
696
|
|
|
695
697
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWebshopTrialExpired);
|
|
696
698
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripMembersTrialExpired); // also mark members
|
|
@@ -703,12 +705,12 @@ export class Organization extends Model {
|
|
|
703
705
|
|
|
704
706
|
if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripMembersTrialExpired)) {
|
|
705
707
|
if (!this.meta.packages.useMembers) {
|
|
706
|
-
const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.TrialMembers)
|
|
708
|
+
const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.TrialMembers);
|
|
707
709
|
if (deactivatedTime !== null && deactivatedTime < 14 * 24 * 60 * 60 * 1000 && deactivatedTime > 7 * 24 * 60 * 60 * 1000) {
|
|
708
710
|
await this.sendEmailTemplate({
|
|
709
711
|
type: EmailTemplateType.OrganizationDripMembersTrialExpired,
|
|
710
|
-
personal: true
|
|
711
|
-
})
|
|
712
|
+
personal: true,
|
|
713
|
+
});
|
|
712
714
|
|
|
713
715
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripMembersTrialExpired);
|
|
714
716
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWebshopTrialExpired); // also mark webshops
|
|
@@ -722,17 +724,17 @@ export class Organization extends Model {
|
|
|
722
724
|
// trial expired reminder (after 10 months)
|
|
723
725
|
if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripTrialExpiredReminder)) {
|
|
724
726
|
if (!this.meta.packages.isPaid && !this.meta.packages.wasPaid) {
|
|
725
|
-
const deactivatedTime1 = this.meta.packages.getDeactivatedTime(STPackageType.TrialWebshops)
|
|
726
|
-
const deactivatedTime2 = this.meta.packages.getDeactivatedTime(STPackageType.TrialMembers)
|
|
727
|
+
const deactivatedTime1 = this.meta.packages.getDeactivatedTime(STPackageType.TrialWebshops);
|
|
728
|
+
const deactivatedTime2 = this.meta.packages.getDeactivatedTime(STPackageType.TrialMembers);
|
|
727
729
|
|
|
728
|
-
const deactivatedTime = deactivatedTime1 && deactivatedTime2 ? Math.max(deactivatedTime1, deactivatedTime2) : (deactivatedTime1 ? deactivatedTime1 : deactivatedTime2)
|
|
730
|
+
const deactivatedTime = deactivatedTime1 && deactivatedTime2 ? Math.max(deactivatedTime1, deactivatedTime2) : (deactivatedTime1 ? deactivatedTime1 : deactivatedTime2);
|
|
729
731
|
|
|
730
732
|
if (deactivatedTime !== null && deactivatedTime > 10 * 30 * 24 * 60 * 60 * 1000 && deactivatedTime < 13 * 31 * 24 * 60 * 60 * 1000) {
|
|
731
733
|
await this.sendEmailTemplate({
|
|
732
734
|
type: EmailTemplateType.OrganizationDripTrialExpiredReminder,
|
|
733
735
|
personal: true,
|
|
734
|
-
bcc: true
|
|
735
|
-
})
|
|
736
|
+
bcc: true,
|
|
737
|
+
});
|
|
736
738
|
|
|
737
739
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripTrialExpiredReminder);
|
|
738
740
|
await this.save();
|
|
@@ -744,14 +746,14 @@ export class Organization extends Model {
|
|
|
744
746
|
|
|
745
747
|
if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripWebshopNotRenewed)) {
|
|
746
748
|
if (!this.meta.packages.useWebshops) {
|
|
747
|
-
const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.Webshops)
|
|
748
|
-
|
|
749
|
-
if (deactivatedTime !== null && deactivatedTime > 30 * 24 * 60 * 60 * 1000 && deactivatedTime < 30*3 * 24 * 60 * 60 * 1000) {
|
|
749
|
+
const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.Webshops);
|
|
750
|
+
|
|
751
|
+
if (deactivatedTime !== null && deactivatedTime > 30 * 24 * 60 * 60 * 1000 && deactivatedTime < 30 * 3 * 24 * 60 * 60 * 1000) {
|
|
750
752
|
await this.sendEmailTemplate({
|
|
751
753
|
type: EmailTemplateType.OrganizationDripWebshopNotRenewed,
|
|
752
754
|
personal: true,
|
|
753
|
-
bcc: true
|
|
754
|
-
})
|
|
755
|
+
bcc: true,
|
|
756
|
+
});
|
|
755
757
|
|
|
756
758
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWebshopNotRenewed);
|
|
757
759
|
await this.save();
|
|
@@ -763,14 +765,14 @@ export class Organization extends Model {
|
|
|
763
765
|
|
|
764
766
|
if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripMembersNotRenewed)) {
|
|
765
767
|
if (!this.meta.packages.useMembers) {
|
|
766
|
-
const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.Members)
|
|
767
|
-
|
|
768
|
-
if (deactivatedTime !== null && deactivatedTime > 30 * 24 * 60 * 60 * 1000 && deactivatedTime < 30*3 * 24 * 60 * 60 * 1000) {
|
|
768
|
+
const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.Members);
|
|
769
|
+
|
|
770
|
+
if (deactivatedTime !== null && deactivatedTime > 30 * 24 * 60 * 60 * 1000 && deactivatedTime < 30 * 3 * 24 * 60 * 60 * 1000) {
|
|
769
771
|
await this.sendEmailTemplate({
|
|
770
772
|
type: EmailTemplateType.OrganizationDripMembersNotRenewed,
|
|
771
773
|
personal: true,
|
|
772
|
-
bcc: true
|
|
773
|
-
})
|
|
774
|
+
bcc: true,
|
|
775
|
+
});
|
|
774
776
|
|
|
775
777
|
this.serverMeta.addEmail(EmailTemplateType.OrganizationDripMembersNotRenewed);
|
|
776
778
|
await this.save();
|
|
@@ -792,18 +794,18 @@ export class Organization extends Model {
|
|
|
792
794
|
return [
|
|
793
795
|
{
|
|
794
796
|
name: sender.name,
|
|
795
|
-
email: sender.email
|
|
796
|
-
}
|
|
797
|
-
]
|
|
797
|
+
email: sender.email,
|
|
798
|
+
},
|
|
799
|
+
];
|
|
798
800
|
}
|
|
799
801
|
|
|
800
|
-
return await this.getAdminToEmails()
|
|
802
|
+
return await this.getAdminToEmails();
|
|
801
803
|
}
|
|
802
804
|
|
|
803
805
|
async getAdmins() {
|
|
804
806
|
// Circular reference fix
|
|
805
807
|
const User = (await import('./User')).User;
|
|
806
|
-
return await User.getAdmins([this.id], {verified: true});
|
|
808
|
+
return await User.getAdmins([this.id], { verified: true });
|
|
807
809
|
}
|
|
808
810
|
|
|
809
811
|
/**
|
|
@@ -813,66 +815,66 @@ export class Organization extends Model {
|
|
|
813
815
|
const admins = await this.getAdmins();
|
|
814
816
|
|
|
815
817
|
// Only full access
|
|
816
|
-
return admins.filter(a => a.permissions && a.permissions.forOrganization(this)?.hasFullAccess())
|
|
818
|
+
return admins.filter(a => a.permissions && a.permissions.forOrganization(this)?.hasFullAccess());
|
|
817
819
|
}
|
|
818
820
|
|
|
819
821
|
/**
|
|
820
822
|
* These email addresess are private
|
|
821
823
|
*/
|
|
822
824
|
async getAdminToEmails(): Promise<EmailInterfaceRecipient[]> {
|
|
823
|
-
const filtered = await this.getFullAdmins()
|
|
825
|
+
const filtered = await this.getFullAdmins();
|
|
824
826
|
|
|
825
|
-
if (STAMHOOFD.environment ===
|
|
827
|
+
if (STAMHOOFD.environment === 'production') {
|
|
826
828
|
if (filtered.length > 1) {
|
|
827
829
|
// remove stamhoofd email addresses
|
|
828
|
-
const f = filtered.flatMap(f => f.getEmailTo()
|
|
830
|
+
const f = filtered.flatMap(f => f.getEmailTo()).filter(e => !e.email.endsWith('@stamhoofd.be') && !e.email.endsWith('@stamhoofd.nl'));
|
|
829
831
|
if (f.length > 0) {
|
|
830
|
-
return f
|
|
832
|
+
return f;
|
|
831
833
|
}
|
|
832
834
|
}
|
|
833
835
|
}
|
|
834
836
|
|
|
835
|
-
return filtered.flatMap(f => f.getEmailTo()
|
|
837
|
+
return filtered.flatMap(f => f.getEmailTo());
|
|
836
838
|
}
|
|
837
839
|
|
|
838
840
|
/**
|
|
839
841
|
* These email addresess are private
|
|
840
842
|
*/
|
|
841
843
|
async getAdminRecipients(): Promise<Recipient[]> {
|
|
842
|
-
let filtered = await this.getFullAdmins()
|
|
844
|
+
let filtered = await this.getFullAdmins();
|
|
843
845
|
|
|
844
|
-
if (STAMHOOFD.environment ===
|
|
846
|
+
if (STAMHOOFD.environment === 'production') {
|
|
845
847
|
if (filtered.length > 1) {
|
|
846
848
|
// remove stamhoofd email addresses
|
|
847
|
-
filtered = filtered.filter(e => !e.email.endsWith(
|
|
849
|
+
filtered = filtered.filter(e => !e.email.endsWith('@stamhoofd.be') && !e.email.endsWith('@stamhoofd.nl'));
|
|
848
850
|
}
|
|
849
851
|
}
|
|
850
852
|
|
|
851
|
-
return filtered.flatMap(f => {
|
|
853
|
+
return filtered.flatMap((f) => {
|
|
852
854
|
return Recipient.create({
|
|
853
855
|
firstName: f.firstName,
|
|
854
856
|
lastName: f.lastName,
|
|
855
857
|
email: f.email,
|
|
856
858
|
replacements: [
|
|
857
859
|
Replacement.create({
|
|
858
|
-
token:
|
|
859
|
-
value: this.name
|
|
860
|
-
})
|
|
861
|
-
]
|
|
862
|
-
})
|
|
863
|
-
}
|
|
860
|
+
token: 'organizationName',
|
|
861
|
+
value: this.name,
|
|
862
|
+
}),
|
|
863
|
+
],
|
|
864
|
+
});
|
|
865
|
+
});
|
|
864
866
|
}
|
|
865
867
|
|
|
866
868
|
/**
|
|
867
869
|
* Return default e-mail address if no email addresses are set.
|
|
868
870
|
*/
|
|
869
871
|
getDefaultFrom(i18n: I18n, withName = true, type: 'transactional' | 'broadcast' = 'broadcast') {
|
|
870
|
-
const domain = type === 'transactional' ? i18n.localizedDomains.defaultTransactionalEmail() : i18n.localizedDomains.defaultBroadcastEmail()
|
|
872
|
+
const domain = type === 'transactional' ? i18n.localizedDomains.defaultTransactionalEmail() : i18n.localizedDomains.defaultBroadcastEmail();
|
|
871
873
|
|
|
872
874
|
if (!withName) {
|
|
873
|
-
return ('noreply-' + this.uri+
|
|
875
|
+
return ('noreply-' + this.uri + '@' + domain);
|
|
874
876
|
}
|
|
875
|
-
return '"'+this.name.replaceAll("
|
|
877
|
+
return '"' + this.name.replaceAll('"', '\\"') + '" <' + ('noreply-' + this.uri + '@' + domain) + '>';
|
|
876
878
|
}
|
|
877
879
|
|
|
878
880
|
/**
|
|
@@ -880,40 +882,42 @@ export class Organization extends Model {
|
|
|
880
882
|
*/
|
|
881
883
|
getEmail(id: string | null, strongDefault = false): { from: string; replyTo: string | undefined } {
|
|
882
884
|
if (id === null) {
|
|
883
|
-
return this.getDefaultEmail(strongDefault)
|
|
885
|
+
return this.getDefaultEmail(strongDefault);
|
|
884
886
|
}
|
|
885
|
-
|
|
887
|
+
|
|
886
888
|
// Send confirmation e-mail
|
|
887
|
-
let from = this.getDefaultFrom(this.i18n, false, strongDefault ? 'transactional' : 'broadcast')
|
|
888
|
-
const sender: OrganizationEmail | undefined = this.privateMeta.emails.find(e => e.id === id)
|
|
889
|
-
let replyTo: string | undefined = undefined
|
|
889
|
+
let from = this.getDefaultFrom(this.i18n, false, strongDefault ? 'transactional' : 'broadcast');
|
|
890
|
+
const sender: OrganizationEmail | undefined = this.privateMeta.emails.find(e => e.id === id);
|
|
891
|
+
let replyTo: string | undefined = undefined;
|
|
890
892
|
|
|
891
893
|
if (sender) {
|
|
892
|
-
replyTo = sender.email
|
|
894
|
+
replyTo = sender.email;
|
|
893
895
|
|
|
894
896
|
// Can we send from this e-mail or reply-to?
|
|
895
|
-
if (replyTo && this.privateMeta.mailDomain && this.privateMeta.mailDomainActive && sender.email.endsWith(
|
|
896
|
-
from = sender.email
|
|
897
|
-
replyTo = undefined
|
|
897
|
+
if (replyTo && this.privateMeta.mailDomain && this.privateMeta.mailDomainActive && sender.email.endsWith('@' + this.privateMeta.mailDomain)) {
|
|
898
|
+
from = sender.email;
|
|
899
|
+
replyTo = undefined;
|
|
898
900
|
}
|
|
899
901
|
|
|
900
902
|
// Include name in form field
|
|
901
903
|
if (sender.name) {
|
|
902
|
-
from = '"'+sender.name.replaceAll("
|
|
903
|
-
}
|
|
904
|
-
|
|
904
|
+
from = '"' + sender.name.replaceAll('"', '\\"') + '" <' + from + '>';
|
|
905
|
+
}
|
|
906
|
+
else {
|
|
907
|
+
from = '"' + this.name.replaceAll('"', '\\"') + '" <' + from + '>';
|
|
905
908
|
}
|
|
906
909
|
|
|
907
910
|
if (replyTo) {
|
|
908
911
|
if (sender.name) {
|
|
909
|
-
replyTo = '"'+sender.name.replaceAll("
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
+
replyTo = '"' + sender.name.replaceAll('"', '\\"') + '" <' + replyTo + '>';
|
|
913
|
+
}
|
|
914
|
+
else {
|
|
915
|
+
replyTo = '"' + this.name.replaceAll('"', '\\"') + '" <' + replyTo + '>';
|
|
912
916
|
}
|
|
913
917
|
}
|
|
914
|
-
return { from, replyTo }
|
|
918
|
+
return { from, replyTo };
|
|
915
919
|
}
|
|
916
|
-
return this.getDefaultEmail(strongDefault)
|
|
920
|
+
return this.getDefaultEmail(strongDefault);
|
|
917
921
|
}
|
|
918
922
|
|
|
919
923
|
/**
|
|
@@ -921,91 +925,94 @@ export class Organization extends Model {
|
|
|
921
925
|
*/
|
|
922
926
|
getDefaultEmail(strongDefault = false): { from: string; replyTo: string | undefined } {
|
|
923
927
|
// Send confirmation e-mail
|
|
924
|
-
let from = strongDefault ? this.getDefaultFrom(this.i18n, false) : this.uri+
|
|
928
|
+
let from = strongDefault ? this.getDefaultFrom(this.i18n, false) : this.uri + '@stamhoofd.email';
|
|
925
929
|
const sender: OrganizationEmail | undefined = this.privateMeta.emails.find(e => e.default) ?? this.privateMeta.emails[0];
|
|
926
|
-
let replyTo: string | undefined = undefined
|
|
930
|
+
let replyTo: string | undefined = undefined;
|
|
927
931
|
|
|
928
932
|
if (sender) {
|
|
929
|
-
replyTo = sender.email
|
|
933
|
+
replyTo = sender.email;
|
|
930
934
|
|
|
931
935
|
// Can we send from this e-mail or reply-to?
|
|
932
|
-
if (replyTo && this.privateMeta.mailDomain && this.privateMeta.mailDomainActive && sender.email.endsWith(
|
|
933
|
-
from = sender.email
|
|
934
|
-
replyTo = undefined
|
|
936
|
+
if (replyTo && this.privateMeta.mailDomain && this.privateMeta.mailDomainActive && sender.email.endsWith('@' + this.privateMeta.mailDomain)) {
|
|
937
|
+
from = sender.email;
|
|
938
|
+
replyTo = undefined;
|
|
935
939
|
}
|
|
936
940
|
|
|
937
941
|
// Include name in form field
|
|
938
942
|
if (sender.name) {
|
|
939
|
-
from = '"'+sender.name.replaceAll("
|
|
940
|
-
}
|
|
941
|
-
|
|
943
|
+
from = '"' + sender.name.replaceAll('"', '\\"') + '" <' + from + '>';
|
|
944
|
+
}
|
|
945
|
+
else {
|
|
946
|
+
from = '"' + this.name.replaceAll('"', '\\"') + '" <' + from + '>';
|
|
942
947
|
}
|
|
943
948
|
|
|
944
949
|
if (replyTo) {
|
|
945
950
|
if (sender.name) {
|
|
946
|
-
replyTo = '"'+sender.name.replaceAll("
|
|
947
|
-
}
|
|
948
|
-
|
|
951
|
+
replyTo = '"' + sender.name.replaceAll('"', '\\"') + '" <' + replyTo + '>';
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
replyTo = '"' + this.name.replaceAll('"', '\\"') + '" <' + replyTo + '>';
|
|
949
955
|
}
|
|
950
956
|
}
|
|
951
|
-
}
|
|
952
|
-
|
|
957
|
+
}
|
|
958
|
+
else {
|
|
959
|
+
from = '"' + this.name.replaceAll('"', '\\"') + '" <' + from + '>';
|
|
953
960
|
}
|
|
954
961
|
|
|
955
962
|
return {
|
|
956
|
-
from, replyTo
|
|
957
|
-
}
|
|
963
|
+
from, replyTo,
|
|
964
|
+
};
|
|
958
965
|
}
|
|
959
966
|
|
|
960
967
|
async getPaymentProviderFor(method: PaymentMethod, config: PrivatePaymentConfiguration): Promise<{
|
|
961
|
-
provider: PaymentProvider | null
|
|
962
|
-
stripeAccount: StripeAccount | null
|
|
963
|
-
}>
|
|
964
|
-
let stripeAccount = (config.stripeAccountId ? (await StripeAccount.getByID(config.stripeAccountId)) : null) ?? null
|
|
968
|
+
provider: PaymentProvider | null;
|
|
969
|
+
stripeAccount: StripeAccount | null;
|
|
970
|
+
}> {
|
|
971
|
+
let stripeAccount = (config.stripeAccountId ? (await StripeAccount.getByID(config.stripeAccountId)) : null) ?? null;
|
|
965
972
|
if (stripeAccount && stripeAccount.organizationId !== this.id) {
|
|
966
|
-
console.warn('Stripe account '+stripeAccount.id+' is not linked to organization '+this.id);
|
|
967
|
-
stripeAccount = null
|
|
973
|
+
console.warn('Stripe account ' + stripeAccount.id + ' is not linked to organization ' + this.id);
|
|
974
|
+
stripeAccount = null;
|
|
968
975
|
}
|
|
969
|
-
const provider = this.privateMeta.getPaymentProviderFor(method, stripeAccount?.meta)
|
|
976
|
+
const provider = this.privateMeta.getPaymentProviderFor(method, stripeAccount?.meta);
|
|
970
977
|
if (provider === null && ![PaymentMethod.Unknown, PaymentMethod.Transfer, PaymentMethod.PointOfSale].includes(method)) {
|
|
971
978
|
if (!stripeAccount && config.stripeAccountId) {
|
|
972
979
|
console.warn('Missing stripe account id ' + config.stripeAccountId);
|
|
973
980
|
}
|
|
974
981
|
throw new SimpleError({
|
|
975
982
|
code: 'payment_provider_not_configured',
|
|
976
|
-
message: 'Payment provider not configured for '+method,
|
|
977
|
-
human: 'Deze betaalmethode werd helaas niet volledig geconfigureerd. Probeer later even opnieuw, neem contact met ons op of kies een andere betaalmethode.'
|
|
978
|
-
})
|
|
983
|
+
message: 'Payment provider not configured for ' + method,
|
|
984
|
+
human: 'Deze betaalmethode werd helaas niet volledig geconfigureerd. Probeer later even opnieuw, neem contact met ons op of kies een andere betaalmethode.',
|
|
985
|
+
});
|
|
979
986
|
}
|
|
980
987
|
|
|
981
988
|
if (provider !== PaymentProvider.Stripe && stripeAccount) {
|
|
982
|
-
stripeAccount = null
|
|
989
|
+
stripeAccount = null;
|
|
983
990
|
}
|
|
984
991
|
return {
|
|
985
992
|
provider,
|
|
986
|
-
stripeAccount
|
|
987
|
-
}
|
|
993
|
+
stripeAccount,
|
|
994
|
+
};
|
|
988
995
|
}
|
|
989
996
|
|
|
990
997
|
async getConnectedPaymentProviders(): Promise<PaymentProvider[]> {
|
|
991
|
-
const allPaymentMethods = Object.values(PaymentMethod)
|
|
992
|
-
const providers: PaymentProvider[] = []
|
|
998
|
+
const allPaymentMethods = Object.values(PaymentMethod);
|
|
999
|
+
const providers: PaymentProvider[] = [];
|
|
993
1000
|
|
|
994
|
-
let stripeAccounts: (StripeAccount|null)[] = await StripeAccount.where({ organizationId: this.id, status: 'active' })
|
|
1001
|
+
let stripeAccounts: (StripeAccount | null)[] = await StripeAccount.where({ organizationId: this.id, status: 'active' });
|
|
995
1002
|
|
|
996
1003
|
if (stripeAccounts.length === 0) {
|
|
997
|
-
stripeAccounts = [null]
|
|
1004
|
+
stripeAccounts = [null];
|
|
998
1005
|
}
|
|
999
1006
|
|
|
1000
1007
|
for (const account of stripeAccounts) {
|
|
1001
1008
|
for (const method of allPaymentMethods) {
|
|
1002
|
-
const provider = this.privateMeta.getPaymentProviderFor(method, account?.meta)
|
|
1009
|
+
const provider = this.privateMeta.getPaymentProviderFor(method, account?.meta);
|
|
1003
1010
|
if (provider && !providers.includes(provider)) {
|
|
1004
|
-
providers.push(provider)
|
|
1011
|
+
providers.push(provider);
|
|
1005
1012
|
}
|
|
1006
1013
|
}
|
|
1007
1014
|
}
|
|
1008
1015
|
|
|
1009
|
-
return providers
|
|
1016
|
+
return providers;
|
|
1010
1017
|
}
|
|
1011
1018
|
}
|