@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
package/src/models/Email.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { column, Model } from '@simonbackx/simple-database';
|
|
2
2
|
import { EditorSmartButton, EditorSmartVariable, EmailAttachment, EmailPreview, EmailRecipientFilter, EmailRecipientFilterType, EmailRecipientsStatus, EmailRecipient as EmailRecipientStruct, EmailStatus, Email as EmailStruct, getExampleRecipient, LimitedFilteredRequest, PaginatedResponse, Recipient, SortItemDirection } from '@stamhoofd/structures';
|
|
3
|
-
import { v4 as uuidv4 } from
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
4
|
|
|
5
5
|
import { AnyDecoder, ArrayDecoder } from '@simonbackx/simple-encoding';
|
|
6
6
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
7
7
|
import { I18n } from '@stamhoofd/backend-i18n';
|
|
8
|
-
import { Email as EmailClass } from
|
|
8
|
+
import { Email as EmailClass } from '@stamhoofd/email';
|
|
9
9
|
import { QueueHandler } from '@stamhoofd/queues';
|
|
10
10
|
import { SQL, SQLWhereSign } from '@stamhoofd/sql';
|
|
11
11
|
import { Formatter } from '@stamhoofd/utility';
|
|
@@ -14,201 +14,198 @@ import { EmailRecipient } from './EmailRecipient';
|
|
|
14
14
|
import { Organization } from './Organization';
|
|
15
15
|
|
|
16
16
|
export class Email extends Model {
|
|
17
|
-
static table =
|
|
17
|
+
static table = 'emails';
|
|
18
18
|
|
|
19
19
|
@column({
|
|
20
|
-
primary: true, type:
|
|
20
|
+
primary: true, type: 'string', beforeSave(value) {
|
|
21
21
|
return value ?? uuidv4();
|
|
22
|
-
}
|
|
22
|
+
},
|
|
23
23
|
})
|
|
24
24
|
id!: string;
|
|
25
25
|
|
|
26
|
-
@column({ type:
|
|
27
|
-
organizationId: string|null = null;
|
|
26
|
+
@column({ type: 'string', nullable: true })
|
|
27
|
+
organizationId: string | null = null;
|
|
28
28
|
|
|
29
|
-
@column({ type:
|
|
30
|
-
userId: string|null = null;
|
|
29
|
+
@column({ type: 'string', nullable: true })
|
|
30
|
+
userId: string | null = null;
|
|
31
31
|
|
|
32
|
-
@column({ type:
|
|
33
|
-
recipientFilter: EmailRecipientFilter = EmailRecipientFilter.create({})
|
|
32
|
+
@column({ type: 'json', decoder: EmailRecipientFilter })
|
|
33
|
+
recipientFilter: EmailRecipientFilter = EmailRecipientFilter.create({});
|
|
34
34
|
|
|
35
|
-
@column({ type:
|
|
36
|
-
subject: string|null
|
|
35
|
+
@column({ type: 'string', nullable: true })
|
|
36
|
+
subject: string | null;
|
|
37
37
|
|
|
38
|
-
/** Raw json structure to edit the template */
|
|
39
|
-
@column({ type:
|
|
38
|
+
/** Raw json structure to edit the template */
|
|
39
|
+
@column({ type: 'json', decoder: AnyDecoder })
|
|
40
40
|
json: any = {};
|
|
41
41
|
|
|
42
|
-
@column({ type:
|
|
43
|
-
html: string|null = null
|
|
42
|
+
@column({ type: 'string', nullable: true })
|
|
43
|
+
html: string | null = null;
|
|
44
44
|
|
|
45
|
-
@column({ type:
|
|
46
|
-
text: string|null = null
|
|
45
|
+
@column({ type: 'string', nullable: true })
|
|
46
|
+
text: string | null = null;
|
|
47
47
|
|
|
48
|
-
@column({ type:
|
|
49
|
-
fromAddress: string|null = null
|
|
48
|
+
@column({ type: 'string', nullable: true })
|
|
49
|
+
fromAddress: string | null = null;
|
|
50
50
|
|
|
51
|
-
@column({ type:
|
|
52
|
-
fromName: string|null = null
|
|
51
|
+
@column({ type: 'string', nullable: true })
|
|
52
|
+
fromName: string | null = null;
|
|
53
53
|
|
|
54
|
-
@column({ type:
|
|
55
|
-
recipientCount: number|null = null
|
|
54
|
+
@column({ type: 'integer', nullable: true })
|
|
55
|
+
recipientCount: number | null = null;
|
|
56
56
|
|
|
57
|
-
@column({ type:
|
|
57
|
+
@column({ type: 'string' })
|
|
58
58
|
status = EmailStatus.Draft;
|
|
59
59
|
|
|
60
|
-
@column({ type:
|
|
60
|
+
@column({ type: 'string' })
|
|
61
61
|
recipientsStatus = EmailRecipientsStatus.NotCreated;
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* todo: ignore automatically
|
|
65
65
|
*/
|
|
66
|
-
@column({ type:
|
|
67
|
-
attachments: EmailAttachment[] = []
|
|
66
|
+
@column({ type: 'json', decoder: new ArrayDecoder(EmailAttachment) })
|
|
67
|
+
attachments: EmailAttachment[] = [];
|
|
68
68
|
|
|
69
|
-
|
|
70
69
|
@column({
|
|
71
|
-
type:
|
|
72
|
-
nullable: true
|
|
70
|
+
type: 'datetime',
|
|
71
|
+
nullable: true,
|
|
73
72
|
})
|
|
74
|
-
sentAt: Date|null = null
|
|
73
|
+
sentAt: Date | null = null;
|
|
75
74
|
|
|
76
75
|
@column({
|
|
77
|
-
type:
|
|
76
|
+
type: 'datetime', beforeSave(old?: any) {
|
|
78
77
|
if (old !== undefined) {
|
|
79
78
|
return old;
|
|
80
79
|
}
|
|
81
|
-
const date = new Date()
|
|
82
|
-
date.setMilliseconds(0)
|
|
83
|
-
return date
|
|
84
|
-
}
|
|
80
|
+
const date = new Date();
|
|
81
|
+
date.setMilliseconds(0);
|
|
82
|
+
return date;
|
|
83
|
+
},
|
|
85
84
|
})
|
|
86
|
-
createdAt: Date
|
|
85
|
+
createdAt: Date;
|
|
87
86
|
|
|
88
87
|
@column({
|
|
89
|
-
type:
|
|
90
|
-
const date = new Date()
|
|
91
|
-
date.setMilliseconds(0)
|
|
92
|
-
return date
|
|
88
|
+
type: 'datetime', beforeSave() {
|
|
89
|
+
const date = new Date();
|
|
90
|
+
date.setMilliseconds(0);
|
|
91
|
+
return date;
|
|
93
92
|
},
|
|
94
|
-
skipUpdate: true
|
|
93
|
+
skipUpdate: true,
|
|
95
94
|
})
|
|
96
|
-
updatedAt: Date
|
|
95
|
+
updatedAt: Date;
|
|
97
96
|
|
|
98
97
|
static recipientLoaders: Map<EmailRecipientFilterType, {
|
|
99
|
-
fetch(request: LimitedFilteredRequest): Promise<PaginatedResponse<EmailRecipientStruct[], LimitedFilteredRequest
|
|
100
|
-
count(request: LimitedFilteredRequest): Promise<number
|
|
101
|
-
}> = new Map()
|
|
98
|
+
fetch(request: LimitedFilteredRequest): Promise<PaginatedResponse<EmailRecipientStruct[], LimitedFilteredRequest>>;
|
|
99
|
+
count(request: LimitedFilteredRequest): Promise<number>;
|
|
100
|
+
}> = new Map();
|
|
102
101
|
|
|
103
102
|
throwIfNotReadyToSend() {
|
|
104
103
|
if (this.subject == null || this.subject.length == 0) {
|
|
105
104
|
throw new SimpleError({
|
|
106
105
|
code: 'invalid_field',
|
|
107
106
|
message: 'Missing subject',
|
|
108
|
-
human: 'Vul een onderwerp in voor je een e-mail verstuurt'
|
|
109
|
-
})
|
|
107
|
+
human: 'Vul een onderwerp in voor je een e-mail verstuurt',
|
|
108
|
+
});
|
|
110
109
|
}
|
|
111
110
|
|
|
112
111
|
if (this.text == null || this.text.length == 0) {
|
|
113
112
|
throw new SimpleError({
|
|
114
113
|
code: 'invalid_field',
|
|
115
114
|
message: 'Missing text',
|
|
116
|
-
human: 'Vul een tekst in voor je een e-mail verstuurt'
|
|
117
|
-
})
|
|
115
|
+
human: 'Vul een tekst in voor je een e-mail verstuurt',
|
|
116
|
+
});
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
if (this.html == null || this.html.length == 0) {
|
|
121
120
|
throw new SimpleError({
|
|
122
121
|
code: 'invalid_field',
|
|
123
122
|
message: 'Missing html',
|
|
124
|
-
human: 'Vul een tekst in voor je een e-mail verstuurt'
|
|
125
|
-
})
|
|
123
|
+
human: 'Vul een tekst in voor je een e-mail verstuurt',
|
|
124
|
+
});
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
if (this.fromAddress == null || this.fromAddress.length == 0) {
|
|
129
128
|
throw new SimpleError({
|
|
130
129
|
code: 'invalid_field',
|
|
131
130
|
message: 'Missing from',
|
|
132
|
-
human: 'Vul een afzender in voor je een e-mail verstuurt'
|
|
133
|
-
})
|
|
131
|
+
human: 'Vul een afzender in voor je een e-mail verstuurt',
|
|
132
|
+
});
|
|
134
133
|
}
|
|
135
134
|
|
|
136
|
-
this.validateAttachments()
|
|
135
|
+
this.validateAttachments();
|
|
137
136
|
}
|
|
138
|
-
|
|
137
|
+
|
|
139
138
|
validateAttachments() {
|
|
140
139
|
// Validate attachments
|
|
141
140
|
const size = this.attachments.reduce((value: number, attachment) => {
|
|
142
|
-
return value + attachment.bytes
|
|
143
|
-
}, 0)
|
|
144
|
-
|
|
145
|
-
if (size > 9.5*1024*1024) {
|
|
141
|
+
return value + attachment.bytes;
|
|
142
|
+
}, 0);
|
|
143
|
+
|
|
144
|
+
if (size > 9.5 * 1024 * 1024) {
|
|
146
145
|
throw new SimpleError({
|
|
147
|
-
code:
|
|
148
|
-
message:
|
|
149
|
-
human:
|
|
150
|
-
field:
|
|
151
|
-
})
|
|
146
|
+
code: 'too_big_attachments',
|
|
147
|
+
message: 'Too big attachments',
|
|
148
|
+
human: 'Jouw bericht is te groot. Grote bijlages verstuur je beter niet via e-mail, je plaatst dan best een link naar de locatie in bv. Google Drive. De maximale grootte van een e-mail is 10MB, inclusief het bericht. Als je grote bestanden verstuurt kan je ze ook proberen te verkleinen.',
|
|
149
|
+
field: 'attachments',
|
|
150
|
+
});
|
|
152
151
|
}
|
|
153
152
|
|
|
154
153
|
const safeContentTypes = [
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
]
|
|
154
|
+
'application/msword',
|
|
155
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
156
|
+
'application/vnd.ms-excel',
|
|
157
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
158
|
+
'application/pdf',
|
|
159
|
+
'image/jpeg',
|
|
160
|
+
'image/png',
|
|
161
|
+
'image/gif',
|
|
162
|
+
];
|
|
164
163
|
|
|
165
164
|
for (const attachment of this.attachments) {
|
|
166
165
|
if (attachment.contentType && !safeContentTypes.includes(attachment.contentType)) {
|
|
167
166
|
throw new SimpleError({
|
|
168
|
-
code:
|
|
169
|
-
message:
|
|
170
|
-
human:
|
|
171
|
-
field:
|
|
172
|
-
})
|
|
167
|
+
code: 'content_type_not_supported',
|
|
168
|
+
message: 'Content-Type not supported',
|
|
169
|
+
human: 'Het bestandstype van jouw bijlage wordt niet ondersteund of is onveilig om in een e-mail te plaatsen. Overweeg om je bestand op bv. Google Drive te zetten en de link in jouw e-mail te zetten.',
|
|
170
|
+
field: 'attachments',
|
|
171
|
+
});
|
|
173
172
|
}
|
|
174
173
|
}
|
|
175
174
|
}
|
|
176
175
|
|
|
177
176
|
getFromAddress() {
|
|
178
177
|
if (!this.fromName) {
|
|
179
|
-
return this.fromAddress
|
|
178
|
+
return this.fromAddress!;
|
|
180
179
|
}
|
|
181
180
|
|
|
182
|
-
const cleanedName = Formatter.emailSenderName(this.fromName)
|
|
181
|
+
const cleanedName = Formatter.emailSenderName(this.fromName);
|
|
183
182
|
if (cleanedName.length < 2) {
|
|
184
|
-
return this.fromAddress
|
|
183
|
+
return this.fromAddress!;
|
|
185
184
|
}
|
|
186
|
-
return '"'+cleanedName+'" <'+this.fromAddress+'>'
|
|
187
|
-
|
|
185
|
+
return '"' + cleanedName + '" <' + this.fromAddress + '>';
|
|
188
186
|
}
|
|
189
187
|
|
|
190
|
-
getDefaultFromAddress(organization?: Organization|null): string {
|
|
191
|
-
const i18n = new I18n(
|
|
192
|
-
let address =
|
|
188
|
+
getDefaultFromAddress(organization?: Organization | null): string {
|
|
189
|
+
const i18n = new I18n('nl', 'BE');
|
|
190
|
+
let address = 'noreply@' + i18n.localizedDomains.defaultBroadcastEmail();
|
|
193
191
|
|
|
194
192
|
if (organization) {
|
|
195
193
|
address = organization.getDefaultFrom(organization.i18n, false, 'broadcast');
|
|
196
194
|
}
|
|
197
195
|
|
|
198
196
|
if (!this.fromName) {
|
|
199
|
-
return address
|
|
197
|
+
return address;
|
|
200
198
|
}
|
|
201
199
|
|
|
202
|
-
const cleanedName = Formatter.emailSenderName(this.fromName)
|
|
200
|
+
const cleanedName = Formatter.emailSenderName(this.fromName);
|
|
203
201
|
if (cleanedName.length < 2) {
|
|
204
|
-
return address
|
|
202
|
+
return address;
|
|
205
203
|
}
|
|
206
|
-
return '"'+cleanedName+'" <'+address+'>'
|
|
207
|
-
|
|
204
|
+
return '"' + cleanedName + '" <' + address + '>';
|
|
208
205
|
}
|
|
209
206
|
|
|
210
207
|
async send() {
|
|
211
|
-
this.throwIfNotReadyToSend()
|
|
208
|
+
this.throwIfNotReadyToSend();
|
|
212
209
|
await this.save();
|
|
213
210
|
|
|
214
211
|
const id = this.id;
|
|
@@ -218,8 +215,8 @@ export class Email extends Model {
|
|
|
218
215
|
throw new SimpleError({
|
|
219
216
|
code: 'not_found',
|
|
220
217
|
message: 'Email not found',
|
|
221
|
-
human: 'De e-mail die je probeert te versturen bestaat niet meer'
|
|
222
|
-
})
|
|
218
|
+
human: 'De e-mail die je probeert te versturen bestaat niet meer',
|
|
219
|
+
});
|
|
223
220
|
}
|
|
224
221
|
if (upToDate.status === EmailStatus.Sent) {
|
|
225
222
|
// Already done
|
|
@@ -227,35 +224,36 @@ export class Email extends Model {
|
|
|
227
224
|
return;
|
|
228
225
|
}
|
|
229
226
|
const organization = upToDate.organizationId ? await Organization.getByID(upToDate.organizationId) : null;
|
|
230
|
-
upToDate.throwIfNotReadyToSend()
|
|
227
|
+
upToDate.throwIfNotReadyToSend();
|
|
231
228
|
|
|
232
|
-
let from = upToDate.getDefaultFromAddress(organization)
|
|
229
|
+
let from = upToDate.getDefaultFromAddress(organization);
|
|
233
230
|
let replyTo: string | null = upToDate.getFromAddress();
|
|
234
231
|
|
|
235
232
|
if (!from) {
|
|
236
233
|
throw new SimpleError({
|
|
237
234
|
code: 'invalid_field',
|
|
238
235
|
message: 'Missing from',
|
|
239
|
-
human: 'Vul een afzender in voor je een e-mail verstuurt'
|
|
240
|
-
})
|
|
236
|
+
human: 'Vul een afzender in voor je een e-mail verstuurt',
|
|
237
|
+
});
|
|
241
238
|
}
|
|
242
239
|
|
|
243
240
|
// Can we send from this e-mail or reply-to?
|
|
244
241
|
if (organization) {
|
|
245
|
-
if (organization.privateMeta.mailDomain && organization.privateMeta.mailDomainActive && upToDate.fromAddress!.endsWith(
|
|
242
|
+
if (organization.privateMeta.mailDomain && organization.privateMeta.mailDomainActive && upToDate.fromAddress!.endsWith('@' + organization.privateMeta.mailDomain)) {
|
|
246
243
|
from = upToDate.getFromAddress();
|
|
247
244
|
replyTo = null;
|
|
248
245
|
}
|
|
249
|
-
}
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
250
248
|
// Platform
|
|
251
249
|
// Is the platform allowed to send from the provided email address?
|
|
252
250
|
const domains = [
|
|
253
251
|
...Object.values(STAMHOOFD.domains.defaultTransactionalEmail ?? {}),
|
|
254
|
-
...Object.values(STAMHOOFD.domains.defaultBroadcastEmail ?? {})
|
|
255
|
-
]
|
|
252
|
+
...Object.values(STAMHOOFD.domains.defaultBroadcastEmail ?? {}),
|
|
253
|
+
];
|
|
256
254
|
|
|
257
255
|
for (const domain of domains) {
|
|
258
|
-
if (upToDate.fromAddress!.endsWith(
|
|
256
|
+
if (upToDate.fromAddress!.endsWith('@' + domain)) {
|
|
259
257
|
from = upToDate.getFromAddress();
|
|
260
258
|
replyTo = null;
|
|
261
259
|
break;
|
|
@@ -263,12 +261,12 @@ export class Email extends Model {
|
|
|
263
261
|
}
|
|
264
262
|
}
|
|
265
263
|
|
|
266
|
-
upToDate.status = EmailStatus.Sending
|
|
267
|
-
upToDate.sentAt = upToDate.sentAt ?? new Date()
|
|
264
|
+
upToDate.status = EmailStatus.Sending;
|
|
265
|
+
upToDate.sentAt = upToDate.sentAt ?? new Date();
|
|
268
266
|
await upToDate.save();
|
|
269
267
|
|
|
270
268
|
// Create recipients if not yet created
|
|
271
|
-
await upToDate.buildRecipients()
|
|
269
|
+
await upToDate.buildRecipients();
|
|
272
270
|
|
|
273
271
|
// Refresh model
|
|
274
272
|
upToDate = await Email.getByID(id);
|
|
@@ -276,16 +274,16 @@ export class Email extends Model {
|
|
|
276
274
|
throw new SimpleError({
|
|
277
275
|
code: 'not_found',
|
|
278
276
|
message: 'Email not found',
|
|
279
|
-
human: 'De e-mail die je probeert te versturen bestaat niet meer'
|
|
280
|
-
})
|
|
277
|
+
human: 'De e-mail die je probeert te versturen bestaat niet meer',
|
|
278
|
+
});
|
|
281
279
|
}
|
|
282
280
|
|
|
283
281
|
if (upToDate.recipientsStatus !== EmailRecipientsStatus.Created) {
|
|
284
282
|
throw new SimpleError({
|
|
285
283
|
code: 'recipients_not_created',
|
|
286
284
|
message: 'Failed to create recipients',
|
|
287
|
-
human: 'Er ging iets mis bij het aanmaken van de afzenders.'
|
|
288
|
-
})
|
|
285
|
+
human: 'Er ging iets mis bij het aanmaken van de afzenders.',
|
|
286
|
+
});
|
|
289
287
|
}
|
|
290
288
|
|
|
291
289
|
// Start actually sending in batches of recipients that are not yet sent
|
|
@@ -294,27 +292,26 @@ export class Email extends Model {
|
|
|
294
292
|
const recipientsSet = new Set<string>();
|
|
295
293
|
|
|
296
294
|
const attachments = upToDate.attachments.map((attachment, index) => {
|
|
297
|
-
let filename =
|
|
298
|
-
|
|
299
|
-
if (attachment.contentType ==
|
|
295
|
+
let filename = 'bijlage-' + index;
|
|
296
|
+
|
|
297
|
+
if (attachment.contentType == 'application/pdf') {
|
|
300
298
|
// tmp solution for pdf only
|
|
301
|
-
filename +=
|
|
299
|
+
filename += '.pdf';
|
|
302
300
|
}
|
|
303
|
-
|
|
301
|
+
|
|
304
302
|
// Correct file name if needed
|
|
305
303
|
if (attachment.filename) {
|
|
306
|
-
filename = attachment.filename.toLowerCase().replace(/[^a-z0-9.]+/g,
|
|
304
|
+
filename = attachment.filename.toLowerCase().replace(/[^a-z0-9.]+/g, '-').replace(/^-+/, '').replace(/-+$/, '');
|
|
307
305
|
}
|
|
308
|
-
|
|
306
|
+
|
|
309
307
|
return {
|
|
310
308
|
filename: filename,
|
|
311
309
|
content: attachment.content,
|
|
312
310
|
contentType: attachment.contentType ?? undefined,
|
|
313
|
-
encoding:
|
|
314
|
-
}
|
|
315
|
-
})
|
|
311
|
+
encoding: 'base64',
|
|
312
|
+
};
|
|
313
|
+
});
|
|
316
314
|
|
|
317
|
-
// eslint-disable-next-line no-constant-condition
|
|
318
315
|
while (true) {
|
|
319
316
|
const data = await SQL.select()
|
|
320
317
|
.from('email_recipients')
|
|
@@ -324,7 +321,7 @@ export class Email extends Model {
|
|
|
324
321
|
.orderBy(SQL.column('id'), 'ASC')
|
|
325
322
|
.limit(batchSize)
|
|
326
323
|
.fetch();
|
|
327
|
-
|
|
324
|
+
|
|
328
325
|
const recipients = EmailRecipient.fromRows(data, 'email_recipients');
|
|
329
326
|
|
|
330
327
|
if (recipients.length == 0) {
|
|
@@ -335,54 +332,55 @@ export class Email extends Model {
|
|
|
335
332
|
|
|
336
333
|
for (const recipient of recipients) {
|
|
337
334
|
if (recipientsSet.has(recipient.id)) {
|
|
338
|
-
console.error('Found duplicate recipient while sending email', recipient.id)
|
|
335
|
+
console.error('Found duplicate recipient while sending email', recipient.id);
|
|
339
336
|
continue;
|
|
340
337
|
}
|
|
341
338
|
|
|
342
339
|
recipientsSet.add(recipient.email);
|
|
343
340
|
idPointer = recipient.id;
|
|
344
341
|
|
|
345
|
-
let promiseResolve: (value: void | PromiseLike<void>) => void
|
|
342
|
+
let promiseResolve: (value: void | PromiseLike<void>) => void;
|
|
346
343
|
const promise = new Promise<void>((resolve) => {
|
|
347
344
|
promiseResolve = resolve;
|
|
348
345
|
});
|
|
349
|
-
sendingPromises.push(promise)
|
|
346
|
+
sendingPromises.push(promise);
|
|
350
347
|
|
|
351
|
-
const callback = async (error: Error|null) => {
|
|
348
|
+
const callback = async (error: Error | null) => {
|
|
352
349
|
if (error === null) {
|
|
353
350
|
// Mark saved
|
|
354
351
|
recipient.sentAt = new Date();
|
|
355
|
-
await recipient.save()
|
|
356
|
-
}
|
|
352
|
+
await recipient.save();
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
357
355
|
recipient.failCount += 1;
|
|
358
356
|
recipient.failErrorMessage = error.message;
|
|
359
357
|
recipient.firstFailedAt = recipient.firstFailedAt ?? new Date();
|
|
360
358
|
recipient.lastFailedAt = new Date();
|
|
361
|
-
await recipient.save()
|
|
359
|
+
await recipient.save();
|
|
362
360
|
}
|
|
363
|
-
promiseResolve()
|
|
364
|
-
}
|
|
361
|
+
promiseResolve();
|
|
362
|
+
};
|
|
365
363
|
|
|
366
364
|
// Do send the email
|
|
367
365
|
// Create e-mail builder
|
|
368
366
|
const builder = await getEmailBuilder(organization ?? null, {
|
|
369
367
|
recipients: [
|
|
370
368
|
Recipient.create({
|
|
371
|
-
...recipient
|
|
372
|
-
})
|
|
369
|
+
...recipient,
|
|
370
|
+
}),
|
|
373
371
|
],
|
|
374
|
-
from,
|
|
372
|
+
from,
|
|
375
373
|
replyTo,
|
|
376
|
-
subject: upToDate.subject!,
|
|
374
|
+
subject: upToDate.subject!,
|
|
377
375
|
html: upToDate.html!,
|
|
378
|
-
type:
|
|
376
|
+
type: 'broadcast',
|
|
379
377
|
attachments,
|
|
380
|
-
callback(error: Error|null
|
|
381
|
-
callback(error).catch(console.error)
|
|
378
|
+
callback(error: Error | null) {
|
|
379
|
+
callback(error).catch(console.error);
|
|
382
380
|
},
|
|
383
|
-
})
|
|
381
|
+
});
|
|
384
382
|
|
|
385
|
-
EmailClass.schedule(builder)
|
|
383
|
+
EmailClass.schedule(builder);
|
|
386
384
|
}
|
|
387
385
|
|
|
388
386
|
await Promise.all(sendingPromises);
|
|
@@ -398,7 +396,7 @@ export class Email extends Model {
|
|
|
398
396
|
|
|
399
397
|
updateCount() {
|
|
400
398
|
const id = this.id;
|
|
401
|
-
QueueHandler.schedule('email-count-'+this.id, async function () {
|
|
399
|
+
QueueHandler.schedule('email-count-' + this.id, async function () {
|
|
402
400
|
let upToDate = await Email.getByID(id);
|
|
403
401
|
|
|
404
402
|
if (!upToDate || upToDate.sentAt || !upToDate.id || upToDate.status !== EmailStatus.Draft) {
|
|
@@ -413,24 +411,23 @@ export class Email extends Model {
|
|
|
413
411
|
|
|
414
412
|
try {
|
|
415
413
|
for (const subfilter of upToDate.recipientFilter.filters) {
|
|
416
|
-
|
|
417
414
|
// Create recipients
|
|
418
415
|
const loader = Email.recipientLoaders.get(subfilter.type);
|
|
419
416
|
|
|
420
417
|
if (!loader) {
|
|
421
|
-
throw new Error('Loader for type ' + subfilter.type+' has not been initialised on the Email model')
|
|
418
|
+
throw new Error('Loader for type ' + subfilter.type + ' has not been initialised on the Email model');
|
|
422
419
|
}
|
|
423
420
|
|
|
424
421
|
const request = new LimitedFilteredRequest({
|
|
425
422
|
filter: subfilter.filter,
|
|
426
|
-
sort: [{key: 'id', order: SortItemDirection.ASC}],
|
|
423
|
+
sort: [{ key: 'id', order: SortItemDirection.ASC }],
|
|
427
424
|
limit: 1,
|
|
428
425
|
search: subfilter.search,
|
|
429
|
-
})
|
|
426
|
+
});
|
|
430
427
|
|
|
431
428
|
const c = await loader.count(request);
|
|
432
|
-
|
|
433
|
-
count += c
|
|
429
|
+
|
|
430
|
+
count += c;
|
|
434
431
|
}
|
|
435
432
|
|
|
436
433
|
// Check if we have a more reliable recipientCount in the meantime
|
|
@@ -444,8 +441,9 @@ export class Email extends Model {
|
|
|
444
441
|
}
|
|
445
442
|
upToDate.recipientCount = count;
|
|
446
443
|
await upToDate.save();
|
|
447
|
-
}
|
|
448
|
-
|
|
444
|
+
}
|
|
445
|
+
catch (e) {
|
|
446
|
+
console.error('Failed to update count for email', id);
|
|
449
447
|
console.error(e);
|
|
450
448
|
}
|
|
451
449
|
}).catch(console.error);
|
|
@@ -453,7 +451,7 @@ export class Email extends Model {
|
|
|
453
451
|
|
|
454
452
|
async buildRecipients() {
|
|
455
453
|
const id = this.id;
|
|
456
|
-
await QueueHandler.schedule('email-build-recipients-'+this.id, async function () {
|
|
454
|
+
await QueueHandler.schedule('email-build-recipients-' + this.id, async function () {
|
|
457
455
|
const upToDate = await Email.getByID(id);
|
|
458
456
|
|
|
459
457
|
if (!upToDate || !upToDate.id) {
|
|
@@ -480,28 +478,27 @@ export class Email extends Model {
|
|
|
480
478
|
await SQL
|
|
481
479
|
.delete()
|
|
482
480
|
.from(
|
|
483
|
-
SQL.table('email_recipients')
|
|
481
|
+
SQL.table('email_recipients'),
|
|
484
482
|
)
|
|
485
483
|
.where(SQL.column('emailId'), upToDate.id);
|
|
486
484
|
|
|
487
485
|
for (const subfilter of upToDate.recipientFilter.filters) {
|
|
488
|
-
|
|
489
486
|
// Create recipients
|
|
490
487
|
const loader = Email.recipientLoaders.get(subfilter.type);
|
|
491
488
|
|
|
492
489
|
if (!loader) {
|
|
493
|
-
throw new Error('Loader for type ' + subfilter.type+' has not been initialised on the Email model')
|
|
490
|
+
throw new Error('Loader for type ' + subfilter.type + ' has not been initialised on the Email model');
|
|
494
491
|
}
|
|
495
492
|
|
|
496
|
-
let request: LimitedFilteredRequest|null = new LimitedFilteredRequest({
|
|
493
|
+
let request: LimitedFilteredRequest | null = new LimitedFilteredRequest({
|
|
497
494
|
filter: subfilter.filter,
|
|
498
|
-
sort: [{key: 'id', order: SortItemDirection.ASC}],
|
|
495
|
+
sort: [{ key: 'id', order: SortItemDirection.ASC }],
|
|
499
496
|
limit: 1000,
|
|
500
497
|
search: subfilter.search,
|
|
501
|
-
})
|
|
498
|
+
});
|
|
502
499
|
|
|
503
500
|
while (request) {
|
|
504
|
-
console.log('Loading email page', subfilter.type, request)
|
|
501
|
+
console.log('Loading email page', subfilter.type, request);
|
|
505
502
|
const response = await loader.fetch(request);
|
|
506
503
|
|
|
507
504
|
count += response.results.length;
|
|
@@ -509,10 +506,10 @@ export class Email extends Model {
|
|
|
509
506
|
for (const item of response.results) {
|
|
510
507
|
const recipient = new EmailRecipient();
|
|
511
508
|
recipient.emailId = upToDate.id;
|
|
512
|
-
recipient.email = item.email
|
|
513
|
-
recipient.firstName = item.firstName
|
|
514
|
-
recipient.lastName = item.lastName
|
|
515
|
-
recipient.replacements = item.replacements
|
|
509
|
+
recipient.email = item.email;
|
|
510
|
+
recipient.firstName = item.firstName;
|
|
511
|
+
recipient.lastName = item.lastName;
|
|
512
|
+
recipient.replacements = item.replacements;
|
|
516
513
|
|
|
517
514
|
await recipient.save();
|
|
518
515
|
}
|
|
@@ -528,8 +525,9 @@ export class Email extends Model {
|
|
|
528
525
|
upToDate.recipientsStatus = EmailRecipientsStatus.Created;
|
|
529
526
|
upToDate.recipientCount = count;
|
|
530
527
|
await upToDate.save();
|
|
531
|
-
}
|
|
532
|
-
|
|
528
|
+
}
|
|
529
|
+
catch (e) {
|
|
530
|
+
console.error('Failed to build recipients for email', id);
|
|
533
531
|
console.error(e);
|
|
534
532
|
upToDate.recipientsStatus = EmailRecipientsStatus.NotCreated;
|
|
535
533
|
await upToDate.save();
|
|
@@ -539,7 +537,7 @@ export class Email extends Model {
|
|
|
539
537
|
|
|
540
538
|
async buildExampleRecipient() {
|
|
541
539
|
const id = this.id;
|
|
542
|
-
await QueueHandler.schedule('email-build-recipients-'+this.id, async function () {
|
|
540
|
+
await QueueHandler.schedule('email-build-recipients-' + this.id, async function () {
|
|
543
541
|
const upToDate = await Email.getByID(id);
|
|
544
542
|
|
|
545
543
|
if (!upToDate || upToDate.sentAt || !upToDate.id) {
|
|
@@ -555,28 +553,27 @@ export class Email extends Model {
|
|
|
555
553
|
await SQL
|
|
556
554
|
.delete()
|
|
557
555
|
.from(
|
|
558
|
-
SQL.table('email_recipients')
|
|
556
|
+
SQL.table('email_recipients'),
|
|
559
557
|
)
|
|
560
558
|
.where(SQL.column('emailId'), upToDate.id);
|
|
561
559
|
|
|
562
560
|
for (const subfilter of upToDate.recipientFilter.filters) {
|
|
563
|
-
|
|
564
561
|
// Create recipients
|
|
565
562
|
const loader = Email.recipientLoaders.get(subfilter.type);
|
|
566
563
|
|
|
567
564
|
if (!loader) {
|
|
568
|
-
throw new Error('Loader for type ' + subfilter.type+' has not been initialised on the Email model')
|
|
565
|
+
throw new Error('Loader for type ' + subfilter.type + ' has not been initialised on the Email model');
|
|
569
566
|
}
|
|
570
567
|
|
|
571
|
-
let request: LimitedFilteredRequest|null = new LimitedFilteredRequest({
|
|
568
|
+
let request: LimitedFilteredRequest | null = new LimitedFilteredRequest({
|
|
572
569
|
filter: subfilter.filter,
|
|
573
|
-
sort: [{key: 'id', order: SortItemDirection.ASC}],
|
|
570
|
+
sort: [{ key: 'id', order: SortItemDirection.ASC }],
|
|
574
571
|
limit: 10,
|
|
575
572
|
search: subfilter.search,
|
|
576
|
-
})
|
|
573
|
+
});
|
|
577
574
|
|
|
578
575
|
while (request) {
|
|
579
|
-
console.log('Loading email page', subfilter.type, request)
|
|
576
|
+
console.log('Loading email page', subfilter.type, request);
|
|
580
577
|
const response = await loader.fetch(request);
|
|
581
578
|
|
|
582
579
|
// Note: it is possible that a result in the database doesn't return a recipient (in memory filtering)
|
|
@@ -585,10 +582,10 @@ export class Email extends Model {
|
|
|
585
582
|
for (const item of response.results) {
|
|
586
583
|
const recipient = new EmailRecipient();
|
|
587
584
|
recipient.emailId = upToDate.id;
|
|
588
|
-
recipient.email = item.email
|
|
589
|
-
recipient.firstName = item.firstName
|
|
590
|
-
recipient.lastName = item.lastName
|
|
591
|
-
recipient.replacements = item.replacements
|
|
585
|
+
recipient.email = item.email;
|
|
586
|
+
recipient.firstName = item.firstName;
|
|
587
|
+
recipient.lastName = item.lastName;
|
|
588
|
+
recipient.replacements = item.replacements;
|
|
592
589
|
await recipient.save();
|
|
593
590
|
return;
|
|
594
591
|
}
|
|
@@ -597,16 +594,17 @@ export class Email extends Model {
|
|
|
597
594
|
}
|
|
598
595
|
}
|
|
599
596
|
|
|
600
|
-
console.warn('No example recipient found for email', id)
|
|
601
|
-
}
|
|
602
|
-
|
|
597
|
+
console.warn('No example recipient found for email', id);
|
|
598
|
+
}
|
|
599
|
+
catch (e) {
|
|
600
|
+
console.error('Failed to build example recipient for email', id);
|
|
603
601
|
console.error(e);
|
|
604
602
|
}
|
|
605
603
|
}).catch(console.error);
|
|
606
604
|
}
|
|
607
605
|
|
|
608
606
|
getStructure() {
|
|
609
|
-
return EmailStruct.create(this)
|
|
607
|
+
return EmailStruct.create(this);
|
|
610
608
|
}
|
|
611
609
|
|
|
612
610
|
async getPreviewStructure() {
|
|
@@ -615,27 +613,27 @@ export class Email extends Model {
|
|
|
615
613
|
.where(SQL.column('emailId'), this.id)
|
|
616
614
|
.first(false);
|
|
617
615
|
|
|
618
|
-
|
|
616
|
+
let recipientRow: EmailRecipientStruct | undefined;
|
|
619
617
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
}
|
|
618
|
+
if (recipient) {
|
|
619
|
+
const emailRecipient = EmailRecipient.fromRow(recipient[EmailRecipient.table]);
|
|
620
|
+
if (emailRecipient) {
|
|
621
|
+
recipientRow = emailRecipient.getStructure();
|
|
625
622
|
}
|
|
623
|
+
}
|
|
626
624
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
625
|
+
if (!recipientRow) {
|
|
626
|
+
recipientRow = getExampleRecipient();
|
|
627
|
+
}
|
|
630
628
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
629
|
+
const smartVariables = recipientRow ? EditorSmartVariable.forRecipient(recipientRow) : [];
|
|
630
|
+
const smartButtons = recipientRow ? EditorSmartButton.forRecipient(recipientRow) : [];
|
|
631
|
+
|
|
632
|
+
return EmailPreview.create({
|
|
633
|
+
...this,
|
|
634
|
+
exampleRecipient: recipientRow,
|
|
635
|
+
smartVariables,
|
|
636
|
+
smartButtons,
|
|
637
|
+
});
|
|
640
638
|
}
|
|
641
639
|
}
|