@stamhoofd/models 2.121.0 → 2.122.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/factories/GroupFactory.d.ts.map +1 -1
- package/dist/factories/GroupFactory.js +1 -1
- package/dist/factories/GroupFactory.js.map +1 -1
- package/dist/factories/OrganizationFactory.d.ts +2 -1
- package/dist/factories/OrganizationFactory.d.ts.map +1 -1
- package/dist/factories/OrganizationFactory.js +9 -1
- package/dist/factories/OrganizationFactory.js.map +1 -1
- package/dist/factories/STPackageFactory.js.map +1 -1
- package/dist/factories/UserFactory.d.ts.map +1 -1
- package/dist/factories/UserFactory.js +2 -2
- package/dist/factories/UserFactory.js.map +1 -1
- package/dist/helpers/EmailBuilder.d.ts.map +1 -1
- package/dist/helpers/EmailBuilder.js +8 -8
- package/dist/helpers/EmailBuilder.js.map +1 -1
- package/dist/helpers/Handlebars.d.ts.map +1 -1
- package/dist/helpers/Handlebars.js +7 -1
- package/dist/helpers/Handlebars.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/migrations/1605262045-import-postcodes.d.ts.map +1 -1
- package/dist/migrations/1605262045-import-postcodes.js +58 -24
- package/dist/migrations/1605262045-import-postcodes.js.map +1 -1
- package/dist/migrations/1605262046-import-postcodes-nl.d.ts.map +1 -1
- package/dist/migrations/1605262046-import-postcodes-nl.js +54 -17
- package/dist/migrations/1605262046-import-postcodes-nl.js.map +1 -1
- package/dist/migrations/1719567881-organization-periodId.sql +2 -0
- package/dist/migrations/1719567882-groups-periodId.sql +2 -0
- package/dist/migrations/1720080975-convert-charset.d.ts +4 -0
- package/dist/migrations/1720080975-convert-charset.d.ts.map +1 -0
- package/dist/migrations/1720080975-convert-charset.js +26 -0
- package/dist/migrations/1720080975-convert-charset.js.map +1 -0
- package/dist/migrations/1720080976-convert-charset-leads.d.ts.map +1 -1
- package/dist/migrations/1720080976-convert-charset-leads.js +11 -10
- package/dist/migrations/1720080976-convert-charset-leads.js.map +1 -1
- package/dist/migrations/1721400546-users-memberId.sql +2 -0
- package/dist/migrations/1722269236-group-waitinglist-id.sql +2 -1
- package/dist/migrations/1722525785-balance-item-paying-organization-id.sql +2 -0
- package/dist/migrations/1722525787-depending-balance-item.sql +2 -0
- package/dist/migrations/1722963554-registration-group-price-and-options.sql +1 -1
- package/dist/migrations/1723652797-payments-paying-organization-id-fk.sql +2 -0
- package/dist/migrations/1733317908-added-missing-organization-fk-on-registrations.sql +2 -0
- package/dist/migrations/1733317910-paying-organization-id-fk.sql +2 -0
- package/dist/migrations/1733504881-negative-invoice-id.sql +6 -0
- package/dist/migrations/1733994455-balance-item-status-open.d.ts +4 -0
- package/dist/migrations/1733994455-balance-item-status-open.d.ts.map +1 -0
- package/dist/migrations/1733994455-balance-item-status-open.js +28 -0
- package/dist/migrations/1733994455-balance-item-status-open.js.map +1 -0
- package/dist/migrations/1769087808-corrected-invoice-user-agent.sql +2 -0
- package/dist/migrations/1769087809-payments-invoice-id.sql +2 -0
- package/dist/migrations/1772033555-balance-item-package-id.sql +2 -0
- package/dist/migrations/1778796615-payments-reversing-payment-id.sql +2 -0
- package/dist/migrations/1779443446-transfer-fees.sql +3 -0
- package/dist/migrations/1779709174-used-register-code-balance-item-id.sql +5 -0
- package/dist/migrations/1779968328-payments-admin-user-id.sql +5 -0
- package/dist/migrations/1779970611-payments-refunded-amount.sql +2 -0
- package/dist/migrations/1779972640-balance-items-failed-at.sql +2 -0
- package/dist/migrations/1780328285-document-template-locked.sql +2 -0
- package/dist/migrations/1780328286-document-locked.sql +2 -0
- package/dist/migrations/1780412083-documents-set-locked.d.ts +4 -0
- package/dist/migrations/1780412083-documents-set-locked.d.ts.map +1 -0
- package/dist/migrations/1780412083-documents-set-locked.js +14 -0
- package/dist/migrations/1780412083-documents-set-locked.js.map +1 -0
- package/dist/migrations/1780928401-v1-groups-migration-data.d.ts +4 -0
- package/dist/migrations/1780928401-v1-groups-migration-data.d.ts.map +1 -0
- package/dist/migrations/1780928401-v1-groups-migration-data.js +44 -0
- package/dist/migrations/1780928401-v1-groups-migration-data.js.map +1 -0
- package/dist/models/BalanceItem.d.ts +7 -2
- package/dist/models/BalanceItem.d.ts.map +1 -1
- package/dist/models/BalanceItem.js +41 -38
- package/dist/models/BalanceItem.js.map +1 -1
- package/dist/models/CachedBalance.d.ts +6 -1
- package/dist/models/CachedBalance.d.ts.map +1 -1
- package/dist/models/CachedBalance.js +3 -2
- package/dist/models/CachedBalance.js.map +1 -1
- package/dist/models/Document.d.ts +4 -0
- package/dist/models/Document.d.ts.map +1 -1
- package/dist/models/Document.js +26 -3
- package/dist/models/Document.js.map +1 -1
- package/dist/models/DocumentTemplate.d.ts +4 -0
- package/dist/models/DocumentTemplate.d.ts.map +1 -1
- package/dist/models/DocumentTemplate.js +37 -1
- package/dist/models/DocumentTemplate.js.map +1 -1
- package/dist/models/Email.d.ts.map +1 -1
- package/dist/models/Email.js +1 -1
- package/dist/models/Email.js.map +1 -1
- package/dist/models/EmailVerificationCode.d.ts.map +1 -1
- package/dist/models/EmailVerificationCode.js +3 -13
- package/dist/models/EmailVerificationCode.js.map +1 -1
- package/dist/models/Event.d.ts +2 -1
- package/dist/models/Event.d.ts.map +1 -1
- package/dist/models/Event.js +3 -0
- package/dist/models/Event.js.map +1 -1
- package/dist/models/EventNotification.d.ts.map +1 -1
- package/dist/models/EventNotification.js +5 -5
- package/dist/models/EventNotification.js.map +1 -1
- package/dist/models/Invoice.d.ts +1 -0
- package/dist/models/Invoice.d.ts.map +1 -1
- package/dist/models/Invoice.js +8 -0
- package/dist/models/Invoice.js.map +1 -1
- package/dist/models/MemberPlatformMembership.d.ts.map +1 -1
- package/dist/models/MemberPlatformMembership.js +9 -0
- package/dist/models/MemberPlatformMembership.js.map +1 -1
- package/dist/models/Order.d.ts.map +1 -1
- package/dist/models/Order.js +1 -0
- package/dist/models/Order.js.map +1 -1
- package/dist/models/Organization.d.ts +23 -25
- package/dist/models/Organization.d.ts.map +1 -1
- package/dist/models/Organization.js +92 -64
- package/dist/models/Organization.js.map +1 -1
- package/dist/models/PasswordToken.d.ts +5 -1
- package/dist/models/PasswordToken.d.ts.map +1 -1
- package/dist/models/PasswordToken.js +18 -17
- package/dist/models/PasswordToken.js.map +1 -1
- package/dist/models/Payment.d.ts +21 -2
- package/dist/models/Payment.d.ts.map +1 -1
- package/dist/models/Payment.js +43 -2
- package/dist/models/Payment.js.map +1 -1
- package/dist/models/Registration.d.ts.map +1 -1
- package/dist/models/Registration.js +3 -3
- package/dist/models/Registration.js.map +1 -1
- package/dist/models/STCredit.d.ts +4 -0
- package/dist/models/STCredit.d.ts.map +1 -1
- package/dist/models/STCredit.js +28 -0
- package/dist/models/STCredit.js.map +1 -1
- package/dist/models/STInvoice.d.ts +7 -1
- package/dist/models/STInvoice.d.ts.map +1 -1
- package/dist/models/STInvoice.js +9 -0
- package/dist/models/STInvoice.js.map +1 -1
- package/dist/models/STPackage.d.ts +4 -0
- package/dist/models/STPackage.d.ts.map +1 -1
- package/dist/models/STPackage.js +12 -1
- package/dist/models/STPackage.js.map +1 -1
- package/dist/models/UsedRegisterCode.d.ts +9 -0
- package/dist/models/UsedRegisterCode.d.ts.map +1 -1
- package/dist/models/UsedRegisterCode.js +31 -0
- package/dist/models/UsedRegisterCode.js.map +1 -1
- package/dist/models/_relations.js +25 -0
- package/dist/models/_relations.js.map +1 -1
- package/dist/models/addresses/City.d.ts +4 -4
- package/dist/models/addresses/City.d.ts.map +1 -1
- package/dist/models/addresses/City.js +6 -6
- package/dist/models/addresses/City.js.map +1 -1
- package/dist/models/addresses/PostalCode.d.ts +2 -2
- package/dist/models/addresses/PostalCode.d.ts.map +1 -1
- package/dist/models/addresses/PostalCode.js +4 -3
- package/dist/models/addresses/PostalCode.js.map +1 -1
- package/dist/models/addresses/Street.d.ts +3 -3
- package/dist/models/addresses/Street.d.ts.map +1 -1
- package/dist/models/addresses/Street.js +4 -4
- package/dist/models/addresses/Street.js.map +1 -1
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +1 -0
- package/dist/models/index.js.map +1 -1
- package/dist/models/v1GroupMigrationData.d.ts +22 -0
- package/dist/models/v1GroupMigrationData.d.ts.map +1 -0
- package/dist/models/v1GroupMigrationData.js +48 -0
- package/dist/models/v1GroupMigrationData.js.map +1 -0
- package/package.json +32 -13
- package/src/factories/GroupFactory.ts +4 -6
- package/src/factories/OrganizationFactory.ts +12 -4
- package/src/factories/STPackageFactory.ts +2 -2
- package/src/factories/UserFactory.ts +4 -5
- package/src/helpers/EmailBuilder.ts +19 -28
- package/src/helpers/Handlebars.ts +6 -1
- package/src/index.ts +0 -1
- package/src/migrations/1605262045-import-postcodes.ts +62 -25
- package/src/migrations/1605262046-import-postcodes-nl.ts +58 -17
- package/src/migrations/1719567881-organization-periodId.sql +2 -0
- package/src/migrations/1719567882-groups-periodId.sql +2 -0
- package/src/migrations/1720080975-convert-charset.ts +34 -0
- package/src/migrations/1720080976-convert-charset-leads.ts +16 -13
- package/src/migrations/1721400546-users-memberId.sql +2 -0
- package/src/migrations/1722269236-group-waitinglist-id.sql +2 -1
- package/src/migrations/1722525785-balance-item-paying-organization-id.sql +2 -0
- package/src/migrations/1722525787-depending-balance-item.sql +2 -0
- package/src/migrations/1722963554-registration-group-price-and-options.sql +1 -1
- package/src/migrations/1723652797-payments-paying-organization-id-fk.sql +2 -0
- package/src/migrations/1733317908-added-missing-organization-fk-on-registrations.sql +2 -0
- package/src/migrations/1733317910-paying-organization-id-fk.sql +2 -0
- package/src/migrations/1733504881-negative-invoice-id.sql +6 -0
- package/src/migrations/1733994455-balance-item-status-open.ts +30 -0
- package/src/migrations/1769087808-corrected-invoice-user-agent.sql +2 -0
- package/src/migrations/1769087809-payments-invoice-id.sql +2 -0
- package/src/migrations/1772033555-balance-item-package-id.sql +2 -0
- package/src/migrations/1778796615-payments-reversing-payment-id.sql +2 -0
- package/src/migrations/1779443446-transfer-fees.sql +3 -0
- package/src/migrations/1779709174-used-register-code-balance-item-id.sql +5 -0
- package/src/migrations/1779968328-payments-admin-user-id.sql +5 -0
- package/src/migrations/1779970611-payments-refunded-amount.sql +2 -0
- package/src/migrations/1779972640-balance-items-failed-at.sql +2 -0
- package/src/migrations/1780328285-document-template-locked.sql +2 -0
- package/src/migrations/1780328286-document-locked.sql +2 -0
- package/src/migrations/1780412083-documents-set-locked.ts +18 -0
- package/src/migrations/1780928401-v1-groups-migration-data.ts +50 -0
- package/src/models/BalanceItem.ts +44 -43
- package/src/models/CachedBalance.test.ts +46 -46
- package/src/models/CachedBalance.ts +7 -7
- package/src/models/Document.ts +34 -13
- package/src/models/DocumentTemplate.ts +56 -17
- package/src/models/Email.test.ts +3 -3
- package/src/models/Email.ts +28 -49
- package/src/models/EmailVerificationCode.ts +8 -22
- package/src/models/Event.ts +6 -4
- package/src/models/EventNotification.ts +6 -6
- package/src/models/Invoice.ts +9 -0
- package/src/models/MemberPlatformMembership.test.ts +70 -0
- package/src/models/MemberPlatformMembership.ts +16 -12
- package/src/models/Order.ts +14 -26
- package/src/models/Organization.ts +122 -93
- package/src/models/PasswordToken.ts +21 -21
- package/src/models/Payment.ts +42 -4
- package/src/models/Registration.ts +3 -3
- package/src/models/STCredit.ts +32 -0
- package/src/models/STInvoice.ts +11 -5
- package/src/models/STPackage.ts +19 -14
- package/src/models/UsedRegisterCode.ts +34 -0
- package/src/models/_relations.ts +29 -0
- package/src/models/addresses/City.ts +8 -6
- package/src/models/addresses/PostalCode.test.ts +1 -0
- package/src/models/addresses/PostalCode.ts +5 -3
- package/src/models/addresses/Street.ts +6 -4
- package/src/models/index.ts +2 -0
- package/src/models/v1GroupMigrationData.ts +43 -0
- package/dist/helpers/MemberMerger.d.ts +0 -14
- package/dist/helpers/MemberMerger.d.ts.map +0 -1
- package/dist/helpers/MemberMerger.js +0 -364
- package/dist/helpers/MemberMerger.js.map +0 -1
- package/dist/migrations/1720080975-convert-charset.sql +0 -85
- package/dist/migrations/1723202126-member-number-index.sql +0 -2
- package/dist/models/OneTimeToken.d.ts +0 -38
- package/dist/models/OneTimeToken.d.ts.map +0 -1
- package/dist/models/OneTimeToken.js +0 -125
- package/dist/models/OneTimeToken.js.map +0 -1
- package/src/helpers/MemberMerger.test.ts +0 -782
- package/src/helpers/MemberMerger.ts +0 -577
- package/src/migrations/1720080975-convert-charset.sql +0 -85
- package/src/migrations/1723202126-member-number-index.sql +0 -2
- package/src/models/OneTimeToken.ts +0 -133
package/src/models/Document.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { DocumentData, DocumentStatus, Document as DocumentStruct, Platform, Ver
|
|
|
3
3
|
import { Formatter } from '@stamhoofd/utility';
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
5
|
|
|
6
|
+
import { SimpleError } from '@simonbackx/simple-errors';
|
|
6
7
|
import { QueryableModel } from '@stamhoofd/sql';
|
|
7
8
|
import { render } from '../helpers/Handlebars.js';
|
|
8
9
|
import type { Member, MemberWithRegistrations, RegistrationWithMember } from './Member.js';
|
|
@@ -38,6 +39,9 @@ export class Document extends QueryableModel {
|
|
|
38
39
|
@column({ type: 'string' })
|
|
39
40
|
status = DocumentStatus.Draft;
|
|
40
41
|
|
|
42
|
+
@column({ type: 'boolean' })
|
|
43
|
+
isLocked = false;
|
|
44
|
+
|
|
41
45
|
/**
|
|
42
46
|
* Assigned when exporting the document
|
|
43
47
|
*/
|
|
@@ -63,6 +67,18 @@ export class Document extends QueryableModel {
|
|
|
63
67
|
})
|
|
64
68
|
updatedAt: Date;
|
|
65
69
|
|
|
70
|
+
override save(options?: Parameters<QueryableModel['save']>[0] & { forceSave?: boolean }): Promise<boolean> {
|
|
71
|
+
if (!options?.forceSave && this.isLocked) {
|
|
72
|
+
throw new SimpleError({
|
|
73
|
+
code: 'locked',
|
|
74
|
+
message: 'Document is locked',
|
|
75
|
+
human: $t(`%1Uc`),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return super.save(options);
|
|
80
|
+
}
|
|
81
|
+
|
|
66
82
|
getStructure() {
|
|
67
83
|
return DocumentStruct.create(this);
|
|
68
84
|
}
|
|
@@ -84,6 +100,7 @@ export class Document extends QueryableModel {
|
|
|
84
100
|
};
|
|
85
101
|
const platformLogo = Platform.shared.config.logoDocuments ?? Platform.shared.config.horizontalLogo ?? Platform.shared.config.squareLogo;
|
|
86
102
|
const organizationLogo = organization.meta.horizontalLogo ?? organization.meta.squareLogo;
|
|
103
|
+
const logo = organizationLogo || platformLogo;
|
|
87
104
|
|
|
88
105
|
if (organizationLogo) {
|
|
89
106
|
data['organization'] = {
|
|
@@ -98,6 +115,10 @@ export class Document extends QueryableModel {
|
|
|
98
115
|
};
|
|
99
116
|
}
|
|
100
117
|
|
|
118
|
+
if (logo) {
|
|
119
|
+
data['logo'] = logo.encode({ version: Version }) ?? null;
|
|
120
|
+
}
|
|
121
|
+
|
|
101
122
|
for (const field of this.data.fieldAnswers.values()) {
|
|
102
123
|
const keys = field.settings.id.split('.');
|
|
103
124
|
let current = data;
|
|
@@ -121,6 +142,11 @@ export class Document extends QueryableModel {
|
|
|
121
142
|
}
|
|
122
143
|
|
|
123
144
|
async updateData(): Promise<void> {
|
|
145
|
+
if (this.isLocked) {
|
|
146
|
+
console.log('Document is locked, skipping update');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
124
150
|
const DocumentTemplate = (await import('./DocumentTemplate.js')).DocumentTemplate;
|
|
125
151
|
const template = await DocumentTemplate.getByID(this.templateId);
|
|
126
152
|
if (!template) {
|
|
@@ -165,8 +191,7 @@ export class Document extends QueryableModel {
|
|
|
165
191
|
await this.updateForRegistrations(loadedMember.registrations.filter(r => r.registeredAt && r.deactivatedAt === null && r.organizationId === organizationId).map(r => r.id), organizationId);
|
|
166
192
|
}
|
|
167
193
|
}
|
|
168
|
-
}
|
|
169
|
-
catch (e) {
|
|
194
|
+
} catch (e) {
|
|
170
195
|
console.error(e);
|
|
171
196
|
}
|
|
172
197
|
}
|
|
@@ -176,13 +201,12 @@ export class Document extends QueryableModel {
|
|
|
176
201
|
console.log('Updating documents for registration', registration.id);
|
|
177
202
|
|
|
178
203
|
const DocumentTemplate = (await import('./DocumentTemplate.js')).DocumentTemplate;
|
|
179
|
-
const templates = await DocumentTemplate.where({ updatesEnabled: 1, organizationId: registration.organizationId });
|
|
204
|
+
const templates = await DocumentTemplate.where({ updatesEnabled: 1, isLocked: 0, organizationId: registration.organizationId });
|
|
180
205
|
|
|
181
206
|
for (const template of templates) {
|
|
182
207
|
await template.updateForRegistration(registration);
|
|
183
208
|
}
|
|
184
|
-
}
|
|
185
|
-
catch (e) {
|
|
209
|
+
} catch (e) {
|
|
186
210
|
console.error(e);
|
|
187
211
|
}
|
|
188
212
|
}
|
|
@@ -208,7 +232,7 @@ export class Document extends QueryableModel {
|
|
|
208
232
|
console.log('Updating documents for updateForRegistrations', registrationIds, organizationId);
|
|
209
233
|
|
|
210
234
|
const DocumentTemplate = (await import('./DocumentTemplate.js')).DocumentTemplate;
|
|
211
|
-
const templates = await DocumentTemplate.where({ updatesEnabled: 1, organizationId });
|
|
235
|
+
const templates = await DocumentTemplate.where({ updatesEnabled: 1, isLocked: 0, organizationId });
|
|
212
236
|
|
|
213
237
|
if (templates.length) {
|
|
214
238
|
const Member = (await import('./Member.js')).Member;
|
|
@@ -219,8 +243,7 @@ export class Document extends QueryableModel {
|
|
|
219
243
|
await template.updateForRegistrations(loadedRegistrations);
|
|
220
244
|
}
|
|
221
245
|
}
|
|
222
|
-
}
|
|
223
|
-
catch (e) {
|
|
246
|
+
} catch (e) {
|
|
224
247
|
console.error(e);
|
|
225
248
|
}
|
|
226
249
|
}
|
|
@@ -230,7 +253,7 @@ export class Document extends QueryableModel {
|
|
|
230
253
|
console.log('Updating documents for group', groupId);
|
|
231
254
|
|
|
232
255
|
const DocumentTemplate = (await import('./DocumentTemplate.js')).DocumentTemplate;
|
|
233
|
-
const templates = await DocumentTemplate.where({ updatesEnabled: 1, organizationId });
|
|
256
|
+
const templates = await DocumentTemplate.where({ updatesEnabled: 1, isLocked: 0, organizationId });
|
|
234
257
|
|
|
235
258
|
if (templates.length) {
|
|
236
259
|
const Member = (await import('./Member.js')).Member;
|
|
@@ -240,8 +263,7 @@ export class Document extends QueryableModel {
|
|
|
240
263
|
await template.updateForRegistrations(registrations);
|
|
241
264
|
}
|
|
242
265
|
}
|
|
243
|
-
}
|
|
244
|
-
catch (e) {
|
|
266
|
+
} catch (e) {
|
|
245
267
|
console.error(e);
|
|
246
268
|
}
|
|
247
269
|
}
|
|
@@ -263,8 +285,7 @@ export class Document extends QueryableModel {
|
|
|
263
285
|
const context = this.buildContext(organization);
|
|
264
286
|
const renderedHtml = await render(htmlTemplate, context);
|
|
265
287
|
return renderedHtml;
|
|
266
|
-
}
|
|
267
|
-
catch (e) {
|
|
288
|
+
} catch (e) {
|
|
268
289
|
console.error('Failed to render document html', e);
|
|
269
290
|
return null;
|
|
270
291
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { column } from '@simonbackx/simple-database';
|
|
2
2
|
import { isSimpleError, isSimpleErrors, SimpleError } from '@simonbackx/simple-errors';
|
|
3
3
|
import { QueueHandler } from '@stamhoofd/queues';
|
|
4
|
-
import type { Parent, RecordAnswer} from '@stamhoofd/structures';
|
|
4
|
+
import type { Parent, RecordAnswer } from '@stamhoofd/structures';
|
|
5
5
|
import { BalanceItemStatus, DocumentData, DocumentPrivateSettings, DocumentSettings, DocumentStatus, DocumentTemplatePrivate, GroupType, NationalRegisterNumberOptOut, RecordAddressAnswer, RecordAnswerDecoder, RecordDateAnswer, RecordPriceAnswer, RecordSettings, RecordTextAnswer, RecordType } from '@stamhoofd/structures';
|
|
6
6
|
import { Formatter, Sorter } from '@stamhoofd/utility';
|
|
7
7
|
import { v4 as uuidv4 } from 'uuid';
|
|
@@ -37,6 +37,9 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
37
37
|
@column({ type: 'string' })
|
|
38
38
|
status = DocumentStatus.Draft;
|
|
39
39
|
|
|
40
|
+
@column({ type: 'boolean' })
|
|
41
|
+
isLocked = false;
|
|
42
|
+
|
|
40
43
|
@column({ type: 'boolean' })
|
|
41
44
|
updatesEnabled = true;
|
|
42
45
|
|
|
@@ -87,6 +90,18 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
87
90
|
})
|
|
88
91
|
updatedAt: Date;
|
|
89
92
|
|
|
93
|
+
override save(options?: Parameters<QueryableModel['save']>[0] & { forceSave?: boolean }): Promise<boolean> {
|
|
94
|
+
if (!options?.forceSave && this.isLocked) {
|
|
95
|
+
throw new SimpleError({
|
|
96
|
+
code: 'locked',
|
|
97
|
+
message: 'Document template is locked',
|
|
98
|
+
human: $t(`%1Uc`),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return super.save(options);
|
|
103
|
+
}
|
|
104
|
+
|
|
90
105
|
getPrivateStructure() {
|
|
91
106
|
return DocumentTemplatePrivate.create(this);
|
|
92
107
|
}
|
|
@@ -363,8 +378,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
363
378
|
found = true;
|
|
364
379
|
fieldAnswers.set(field.id, clone);
|
|
365
380
|
break;
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
381
|
+
} else {
|
|
368
382
|
console.warn('Found type mismatch for default data: ' + linkedToMemberAnswerSettingsId + ' - ' + field.id);
|
|
369
383
|
}
|
|
370
384
|
}
|
|
@@ -412,8 +426,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
412
426
|
for (const answer of fieldAnswers.values()) {
|
|
413
427
|
try {
|
|
414
428
|
answer.validate();
|
|
415
|
-
}
|
|
416
|
-
catch (e) {
|
|
429
|
+
} catch (e) {
|
|
417
430
|
missingData = true;
|
|
418
431
|
|
|
419
432
|
console.log('Missing data because of validation error', e, answer, answer.settings);
|
|
@@ -453,6 +466,14 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
453
466
|
}
|
|
454
467
|
|
|
455
468
|
async updateForRegistration(registration: RegistrationWithMember, existingDocuments?: Document[]): Promise<Document[]> {
|
|
469
|
+
if (this.isLocked) {
|
|
470
|
+
throw new SimpleError({
|
|
471
|
+
code: 'locked',
|
|
472
|
+
message: 'Document template is locked',
|
|
473
|
+
human: $t(`%1Uc`),
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
456
477
|
existingDocuments = existingDocuments !== undefined ? existingDocuments : await Document.where({ templateId: this.id, registrationId: registration.id }, { limit: 5 });
|
|
457
478
|
|
|
458
479
|
if (!this.checkRegistrationIncluded(registration)) {
|
|
@@ -549,8 +570,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
549
570
|
if (age > this.settings.maxAge) {
|
|
550
571
|
return false;
|
|
551
572
|
}
|
|
552
|
-
}
|
|
553
|
-
else {
|
|
573
|
+
} else {
|
|
554
574
|
console.warn('Missing registration.startDate in fieldAnswers when checking maxAge');
|
|
555
575
|
}
|
|
556
576
|
}
|
|
@@ -581,11 +601,20 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
581
601
|
async buildAll({ generateNumbers = false } = {}) {
|
|
582
602
|
QueueHandler.abort('documents-build-all/' + this.id);
|
|
583
603
|
return await QueueHandler.schedule('documents-build-all/' + this.id, async ({ abort }) => {
|
|
604
|
+
if (this.isLocked) {
|
|
605
|
+
return await Document.where({ templateId: this.id });
|
|
606
|
+
}
|
|
607
|
+
|
|
584
608
|
if (!this.updatesEnabled) {
|
|
585
609
|
// Check status
|
|
586
610
|
const documents = await Document.where({ templateId: this.id });
|
|
587
611
|
for (const document of documents) {
|
|
588
612
|
abort.throwIfAborted();
|
|
613
|
+
|
|
614
|
+
if (document.isLocked) {
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
|
|
589
618
|
await this.updateAnswers(document); // Only update global data
|
|
590
619
|
if (document.status === DocumentStatus.Draft || document.status === DocumentStatus.Published) {
|
|
591
620
|
document.status = this.status;
|
|
@@ -597,6 +626,11 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
597
626
|
if (generateNumbers) {
|
|
598
627
|
for (const document of documents) {
|
|
599
628
|
abort.throwIfAborted();
|
|
629
|
+
|
|
630
|
+
if (document.isLocked) {
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
|
|
600
634
|
if (document.number === null && document.status === DocumentStatus.Published) {
|
|
601
635
|
document.number = this.nextNumberForDocuments(documents);
|
|
602
636
|
await document.save();
|
|
@@ -627,11 +661,15 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
627
661
|
const documents = await Document.where({ templateId: this.id });
|
|
628
662
|
for (const document of documents) {
|
|
629
663
|
abort.throwIfAborted();
|
|
664
|
+
|
|
665
|
+
if (document.isLocked) {
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
|
|
630
669
|
if (!documentSet.has(document.id)) {
|
|
631
670
|
if (document.number === null) {
|
|
632
671
|
await document.delete();
|
|
633
|
-
}
|
|
634
|
-
else {
|
|
672
|
+
} else {
|
|
635
673
|
document.status = DocumentStatus.Deleted;
|
|
636
674
|
await document.save();
|
|
637
675
|
}
|
|
@@ -644,6 +682,11 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
644
682
|
if (generateNumbers) {
|
|
645
683
|
for (const document of allDocuments) {
|
|
646
684
|
abort.throwIfAborted();
|
|
685
|
+
|
|
686
|
+
if (document.isLocked) {
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
|
|
647
690
|
if (document.number === null && document.status === DocumentStatus.Published) {
|
|
648
691
|
document.number = this.nextNumberForDocuments(allDocuments);
|
|
649
692
|
await document.save();
|
|
@@ -733,8 +776,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
733
776
|
const context = await this.buildContext(organization);
|
|
734
777
|
const renderedHtml = await render(this.privateSettings.templateDefinition.xmlExport, context);
|
|
735
778
|
return renderedHtml;
|
|
736
|
-
}
|
|
737
|
-
catch (e) {
|
|
779
|
+
} catch (e) {
|
|
738
780
|
if (isSimpleError(e) || isSimpleErrors(e)) {
|
|
739
781
|
throw e;
|
|
740
782
|
}
|
|
@@ -753,8 +795,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
753
795
|
answer.settings = field;
|
|
754
796
|
try {
|
|
755
797
|
answer.validate();
|
|
756
|
-
}
|
|
757
|
-
catch (e) {
|
|
798
|
+
} catch (e) {
|
|
758
799
|
// Invalid
|
|
759
800
|
return false;
|
|
760
801
|
}
|
|
@@ -774,8 +815,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
774
815
|
if (!existing.isReviewedAfter(addAnswer)) {
|
|
775
816
|
newAnswers.set(addAnswer.settings.id, addAnswer);
|
|
776
817
|
}
|
|
777
|
-
}
|
|
778
|
-
else {
|
|
818
|
+
} else {
|
|
779
819
|
newAnswers.set(addAnswer.settings.id, addAnswer);
|
|
780
820
|
}
|
|
781
821
|
}
|
|
@@ -786,8 +826,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
786
826
|
if (document.status !== DocumentStatus.Deleted) {
|
|
787
827
|
if (!complete) {
|
|
788
828
|
document.status = DocumentStatus.MissingData;
|
|
789
|
-
}
|
|
790
|
-
else {
|
|
829
|
+
} else {
|
|
791
830
|
if (document.status === DocumentStatus.MissingData) {
|
|
792
831
|
document.status = this.status;
|
|
793
832
|
}
|
package/src/models/Email.test.ts
CHANGED
|
@@ -896,7 +896,7 @@ describe('Model.Email', () => {
|
|
|
896
896
|
organizationId: organization.id,
|
|
897
897
|
type: BalanceItemType.Other,
|
|
898
898
|
amount: 2,
|
|
899
|
-
unitPrice:
|
|
899
|
+
unitPrice: 12_99_00,
|
|
900
900
|
description: 'Test balance item',
|
|
901
901
|
}).create();
|
|
902
902
|
await CachedBalance.updateForUsers(organization.id, [existingUser.id]);
|
|
@@ -940,12 +940,12 @@ describe('Model.Email', () => {
|
|
|
940
940
|
// Check if the table is correct
|
|
941
941
|
expect(EmailMocker.getSucceededEmail(0).html).toMatch('<table');
|
|
942
942
|
expect(EmailMocker.getSucceededEmail(0).html).toMatch('2 x '); // amount
|
|
943
|
-
expect(EmailMocker.getSucceededEmail(0).html).toMatch(Formatter.price(
|
|
943
|
+
expect(EmailMocker.getSucceededEmail(0).html).toMatch(Formatter.price(12_99_00)); // unit price
|
|
944
944
|
expect(EmailMocker.getSucceededEmail(0).html).toMatch('<td>' + expectedAmount); // total price in table
|
|
945
945
|
expect(EmailMocker.getSucceededEmail(0).html).toMatch('Test balance item'); // description
|
|
946
946
|
|
|
947
947
|
expect(EmailMocker.getSucceededEmail(0).text).toMatch('2 x '); // amount
|
|
948
|
-
expect(EmailMocker.getSucceededEmail(0).text).toMatch(Formatter.price(
|
|
948
|
+
expect(EmailMocker.getSucceededEmail(0).text).toMatch(Formatter.price(12_99_00)); // unit price
|
|
949
949
|
expect(EmailMocker.getSucceededEmail(0).text).toMatch(expectedAmount); // total price in table
|
|
950
950
|
expect(EmailMocker.getSucceededEmail(0).text?.toLowerCase()).toMatch('test balance item'); // description
|
|
951
951
|
}, 15_000);
|
package/src/models/Email.ts
CHANGED
|
@@ -23,11 +23,9 @@ type Attachment = { filename: string; path?: string; href?: string; content?: st
|
|
|
23
23
|
function errorToSimpleErrors(e: unknown) {
|
|
24
24
|
if (isSimpleErrors(e)) {
|
|
25
25
|
return e;
|
|
26
|
-
}
|
|
27
|
-
else if (isSimpleError(e)) {
|
|
26
|
+
} else if (isSimpleError(e)) {
|
|
28
27
|
return new SimpleErrors(e);
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
28
|
+
} else {
|
|
31
29
|
return new SimpleErrors(
|
|
32
30
|
new SimpleError({
|
|
33
31
|
code: 'unknown_error',
|
|
@@ -471,22 +469,22 @@ export class Email extends QueryableModel {
|
|
|
471
469
|
case 'hard-bounce': {
|
|
472
470
|
base.set('hardBouncesCount',
|
|
473
471
|
SQL.calculation(SQL.column('hardBouncesCount'))
|
|
474
|
-
.add(readDynamicSQLExpression(1))
|
|
475
|
-
|
|
472
|
+
.add(readDynamicSQLExpression(1)),
|
|
473
|
+
);
|
|
476
474
|
break;
|
|
477
475
|
}
|
|
478
476
|
case 'soft-bounce': {
|
|
479
477
|
base.set('softBouncesCount',
|
|
480
478
|
SQL.calculation(SQL.column('softBouncesCount'))
|
|
481
|
-
.add(readDynamicSQLExpression(1))
|
|
482
|
-
|
|
479
|
+
.add(readDynamicSQLExpression(1)),
|
|
480
|
+
);
|
|
483
481
|
break;
|
|
484
482
|
}
|
|
485
483
|
case 'complaint': {
|
|
486
484
|
base.set('spamComplaintsCount',
|
|
487
485
|
SQL.calculation(SQL.column('spamComplaintsCount'))
|
|
488
|
-
.add(readDynamicSQLExpression(1))
|
|
489
|
-
|
|
486
|
+
.add(readDynamicSQLExpression(1)),
|
|
487
|
+
);
|
|
490
488
|
break;
|
|
491
489
|
}
|
|
492
490
|
}
|
|
@@ -604,8 +602,7 @@ export class Email extends QueryableModel {
|
|
|
604
602
|
});
|
|
605
603
|
if (waitForSending) {
|
|
606
604
|
return await this.resumeSending();
|
|
607
|
-
}
|
|
608
|
-
else {
|
|
605
|
+
} else {
|
|
609
606
|
this.resumeSending().catch(console.error);
|
|
610
607
|
}
|
|
611
608
|
return this;
|
|
@@ -642,8 +639,7 @@ export class Email extends QueryableModel {
|
|
|
642
639
|
contentType: attachment.contentType ?? undefined,
|
|
643
640
|
encoding: 'base64',
|
|
644
641
|
});
|
|
645
|
-
}
|
|
646
|
-
else {
|
|
642
|
+
} else {
|
|
647
643
|
// Note: because we send lots of emails, we better download the file here so we can reuse it in every email instead of downloading it every time
|
|
648
644
|
const withSigned = await attachment.file!.withSignedUrl();
|
|
649
645
|
if (!withSigned || !withSigned.signedUrl) {
|
|
@@ -655,12 +651,11 @@ export class Email extends QueryableModel {
|
|
|
655
651
|
}
|
|
656
652
|
|
|
657
653
|
const filePath = withSigned.signedUrl;
|
|
658
|
-
let fileBuffer: Buffer | null
|
|
654
|
+
let fileBuffer: Buffer | null;
|
|
659
655
|
try {
|
|
660
656
|
const response = await fetch(filePath);
|
|
661
657
|
fileBuffer = Buffer.from(await response.arrayBuffer());
|
|
662
|
-
}
|
|
663
|
-
catch (e) {
|
|
658
|
+
} catch (e) {
|
|
664
659
|
throw new SimpleError({
|
|
665
660
|
code: 'attachment_not_found',
|
|
666
661
|
message: 'Attachment not found',
|
|
@@ -707,8 +702,7 @@ export class Email extends QueryableModel {
|
|
|
707
702
|
// Update repacements that have been generated
|
|
708
703
|
recipient.replacements = virtualRecipient.replacements;
|
|
709
704
|
await recipient.save();
|
|
710
|
-
}
|
|
711
|
-
else {
|
|
705
|
+
} else {
|
|
712
706
|
recipient.failCount += 1;
|
|
713
707
|
recipient.failErrorMessage = error.message;
|
|
714
708
|
if (recipient.failError) {
|
|
@@ -719,8 +713,7 @@ export class Email extends QueryableModel {
|
|
|
719
713
|
recipient.lastFailedAt = new Date();
|
|
720
714
|
await recipient.save();
|
|
721
715
|
}
|
|
722
|
-
}
|
|
723
|
-
catch (e) {
|
|
716
|
+
} catch (e) {
|
|
724
717
|
console.error(e);
|
|
725
718
|
}
|
|
726
719
|
promiseResolve();
|
|
@@ -761,8 +754,7 @@ export class Email extends QueryableModel {
|
|
|
761
754
|
console.log('Email already sent, skipping...', upToDate.id);
|
|
762
755
|
return upToDate;
|
|
763
756
|
}
|
|
764
|
-
}
|
|
765
|
-
else {
|
|
757
|
+
} else {
|
|
766
758
|
if (singleRecipientId) {
|
|
767
759
|
// Not possible
|
|
768
760
|
throw new SimpleError({
|
|
@@ -786,8 +778,7 @@ export class Email extends QueryableModel {
|
|
|
786
778
|
await upToDate.save();
|
|
787
779
|
return upToDate;
|
|
788
780
|
}
|
|
789
|
-
}
|
|
790
|
-
else if (upToDate.status !== EmailStatus.Queued) {
|
|
781
|
+
} else if (upToDate.status !== EmailStatus.Queued) {
|
|
791
782
|
console.error('Email is not queued or sending, cannot send', upToDate.id, upToDate.status);
|
|
792
783
|
return upToDate;
|
|
793
784
|
}
|
|
@@ -888,8 +879,7 @@ export class Email extends QueryableModel {
|
|
|
888
879
|
|
|
889
880
|
try {
|
|
890
881
|
await upToDate.save();
|
|
891
|
-
}
|
|
892
|
-
finally {
|
|
882
|
+
} finally {
|
|
893
883
|
isSavingStatus = false;
|
|
894
884
|
}
|
|
895
885
|
}
|
|
@@ -938,8 +928,7 @@ export class Email extends QueryableModel {
|
|
|
938
928
|
// Failed or soft-failed
|
|
939
929
|
if (recipient.failError && isSoftEmailRecipientError(recipient.failError)) {
|
|
940
930
|
softFailedCount += 1;
|
|
941
|
-
}
|
|
942
|
-
else {
|
|
931
|
+
} else {
|
|
943
932
|
failedCount += 1;
|
|
944
933
|
}
|
|
945
934
|
skipped++;
|
|
@@ -957,13 +946,11 @@ export class Email extends QueryableModel {
|
|
|
957
946
|
if (recipient.sentAt) {
|
|
958
947
|
succeededCount += 1;
|
|
959
948
|
await saveStatus();
|
|
960
|
-
}
|
|
961
|
-
else {
|
|
949
|
+
} else {
|
|
962
950
|
// Failed or soft-failed
|
|
963
951
|
if (recipient.failError && isSoftEmailRecipientError(recipient.failError)) {
|
|
964
952
|
softFailedCount += 1;
|
|
965
|
-
}
|
|
966
|
-
else {
|
|
953
|
+
} else {
|
|
967
954
|
failedCount += 1;
|
|
968
955
|
}
|
|
969
956
|
await saveStatus();
|
|
@@ -973,14 +960,12 @@ export class Email extends QueryableModel {
|
|
|
973
960
|
|
|
974
961
|
if (sendingPromises.length > 0 || skipped > 0) {
|
|
975
962
|
await Promise.all(sendingPromises);
|
|
976
|
-
}
|
|
977
|
-
else {
|
|
963
|
+
} else {
|
|
978
964
|
break;
|
|
979
965
|
}
|
|
980
966
|
}
|
|
981
967
|
}
|
|
982
|
-
}
|
|
983
|
-
catch (e) {
|
|
968
|
+
} catch (e) {
|
|
984
969
|
if (!upToDate) {
|
|
985
970
|
throw e;
|
|
986
971
|
}
|
|
@@ -1023,8 +1008,7 @@ export class Email extends QueryableModel {
|
|
|
1023
1008
|
human: $t(`%1EG`),
|
|
1024
1009
|
}),
|
|
1025
1010
|
);
|
|
1026
|
-
}
|
|
1027
|
-
else {
|
|
1011
|
+
} else {
|
|
1028
1012
|
upToDate.status = EmailStatus.Sent;
|
|
1029
1013
|
upToDate.emailErrors = null;
|
|
1030
1014
|
}
|
|
@@ -1115,8 +1099,7 @@ export class Email extends QueryableModel {
|
|
|
1115
1099
|
await upToDate.save();
|
|
1116
1100
|
|
|
1117
1101
|
console.log('Updated recipient count for email', id, 'to', count);
|
|
1118
|
-
}
|
|
1119
|
-
catch (e) {
|
|
1102
|
+
} catch (e) {
|
|
1120
1103
|
if (isAbortedError(e)) {
|
|
1121
1104
|
return;
|
|
1122
1105
|
}
|
|
@@ -1263,8 +1246,7 @@ export class Email extends QueryableModel {
|
|
|
1263
1246
|
recipient.replacements = merged;
|
|
1264
1247
|
|
|
1265
1248
|
break;
|
|
1266
|
-
}
|
|
1267
|
-
else {
|
|
1249
|
+
} else {
|
|
1268
1250
|
console.log('Could not merge duplicate email recipient', item.email, other.id, 'keeping both', other.replacements, item.replacements);
|
|
1269
1251
|
}
|
|
1270
1252
|
}
|
|
@@ -1283,8 +1265,7 @@ export class Email extends QueryableModel {
|
|
|
1283
1265
|
|
|
1284
1266
|
if (!recipient.email || duplicateOfRecipientId) {
|
|
1285
1267
|
countWithoutEmail += 1;
|
|
1286
|
-
}
|
|
1287
|
-
else {
|
|
1268
|
+
} else {
|
|
1288
1269
|
count += 1;
|
|
1289
1270
|
}
|
|
1290
1271
|
}
|
|
@@ -1299,8 +1280,7 @@ export class Email extends QueryableModel {
|
|
|
1299
1280
|
upToDate.recipientsErrors = null;
|
|
1300
1281
|
upToDate.membersCount = membersSet.size;
|
|
1301
1282
|
await upToDate.save();
|
|
1302
|
-
}
|
|
1303
|
-
catch (e: unknown) {
|
|
1283
|
+
} catch (e: unknown) {
|
|
1304
1284
|
console.error('Failed to build recipients for email', id);
|
|
1305
1285
|
console.error(e);
|
|
1306
1286
|
upToDate.recipientsStatus = EmailRecipientsStatus.NotCreated;
|
|
@@ -1381,8 +1361,7 @@ export class Email extends QueryableModel {
|
|
|
1381
1361
|
}
|
|
1382
1362
|
|
|
1383
1363
|
console.warn('No example recipient found for email', id);
|
|
1384
|
-
}
|
|
1385
|
-
catch (e) {
|
|
1364
|
+
} catch (e) {
|
|
1386
1365
|
console.error('Failed to build example recipient for email', id);
|
|
1387
1366
|
console.error(e);
|
|
1388
1367
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { column } from '@simonbackx/simple-database';
|
|
2
2
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
3
|
-
import type {I18n} from '@stamhoofd/backend-i18n';
|
|
3
|
+
import type { I18n } from '@stamhoofd/backend-i18n';
|
|
4
4
|
import { QueryableModel } from '@stamhoofd/sql';
|
|
5
|
-
import { EmailTemplateType, Recipient, Replacement } from '@stamhoofd/structures';
|
|
5
|
+
import { appToUri, EmailTemplateType, getAppHost, Recipient, Replacement } from '@stamhoofd/structures';
|
|
6
6
|
import basex from 'base-x';
|
|
7
7
|
import crypto from 'crypto';
|
|
8
8
|
import { v4 as uuidv4 } from 'uuid';
|
|
9
9
|
import { sendEmailTemplate } from '../helpers/EmailBuilder.js';
|
|
10
10
|
import { Platform } from './Platform.js';
|
|
11
|
-
import type {User} from './User.js';
|
|
12
|
-
import type {Organization} from './Organization.js';
|
|
11
|
+
import type { User } from './User.js';
|
|
12
|
+
import type { Organization } from './Organization.js';
|
|
13
13
|
|
|
14
14
|
const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
15
15
|
const bs58 = basex(ALPHABET);
|
|
@@ -121,20 +121,8 @@ export class EmailVerificationCode extends QueryableModel {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
getEmailVerificationUrl(user: User, organization: Organization | null, i18n: I18n) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
host = 'https://' + (STAMHOOFD.domains.dashboard ?? 'stamhoofd.app') + '/' + i18n.locale;
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
// Add language if different than default
|
|
130
|
-
host = 'https://' + organization.getHost();
|
|
131
|
-
|
|
132
|
-
if (i18n.language !== organization.i18n.language) {
|
|
133
|
-
host += '/' + i18n.language;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return host + '/verify-email' + (user.organizationPermissions && this.organizationId ? '/' + encodeURIComponent(this.organizationId) : '') + '?code=' + encodeURIComponent(this.code) + '&token=' + encodeURIComponent(this.token);
|
|
124
|
+
const host = getAppHost('verify-email', organization, !!user.permissions, i18n);
|
|
125
|
+
return 'https://' + host + '?code=' + encodeURIComponent(this.code) + '&token=' + encodeURIComponent(this.token) + '&email=' + encodeURIComponent(this.email);
|
|
138
126
|
}
|
|
139
127
|
|
|
140
128
|
/**
|
|
@@ -283,8 +271,7 @@ export class EmailVerificationCode extends QueryableModel {
|
|
|
283
271
|
},
|
|
284
272
|
type: 'transactional',
|
|
285
273
|
});
|
|
286
|
-
}
|
|
287
|
-
else {
|
|
274
|
+
} else {
|
|
288
275
|
await sendEmailTemplate(organization, {
|
|
289
276
|
recipients: [
|
|
290
277
|
Recipient.create({
|
|
@@ -359,8 +346,7 @@ export class EmailVerificationCode extends QueryableModel {
|
|
|
359
346
|
|
|
360
347
|
// Expire in 3 hours
|
|
361
348
|
verificationCode.expiresAt = new Date(new Date().getTime() + 1000 * 60 * 60 * 3);
|
|
362
|
-
}
|
|
363
|
-
else {
|
|
349
|
+
} else {
|
|
364
350
|
verificationCode = verificationCodes[0];
|
|
365
351
|
|
|
366
352
|
if (verificationCode.email !== email || verificationCode.expiresAt < new Date(new Date().getTime() - 15 * 60 * 1000) || verificationCode.tries >= EmailVerificationCode.MAX_TRIES) {
|
package/src/models/Event.ts
CHANGED
|
@@ -68,6 +68,10 @@ export class Event extends QueryableModel {
|
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
get slug() {
|
|
72
|
+
return this.getStructure().slug;
|
|
73
|
+
}
|
|
74
|
+
|
|
71
75
|
/**
|
|
72
76
|
* @deprecated
|
|
73
77
|
*/
|
|
@@ -101,8 +105,7 @@ export class Event extends QueryableModel {
|
|
|
101
105
|
group.settings.requireOrganizationIds = [this.organizationId];
|
|
102
106
|
group.settings.requireOrganizationTags = [];
|
|
103
107
|
group.settings.requirePlatformMembershipOn = null;
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
108
|
+
} else {
|
|
106
109
|
group.settings.requireOrganizationTags = this.meta.organizationTagIds ?? [];
|
|
107
110
|
|
|
108
111
|
// Everyone can register
|
|
@@ -118,8 +121,7 @@ export class Event extends QueryableModel {
|
|
|
118
121
|
if (waitingList) {
|
|
119
122
|
if (group.settings.allowRegistrationsByOrganization) {
|
|
120
123
|
waitingList.settings.allowRegistrationsByOrganization = true;
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
124
|
+
} else {
|
|
123
125
|
waitingList.settings.allowRegistrationsByOrganization = false;
|
|
124
126
|
}
|
|
125
127
|
await this.syncGroupRequirements(waitingList);
|