@stamhoofd/models 2.79.7 → 2.80.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/EmailTemplateFactory.d.ts +18 -0
- package/dist/src/factories/EmailTemplateFactory.d.ts.map +1 -0
- package/dist/src/factories/EmailTemplateFactory.js +43 -0
- package/dist/src/factories/EmailTemplateFactory.js.map +1 -0
- package/dist/src/factories/EventFactory.d.ts +17 -0
- package/dist/src/factories/EventFactory.d.ts.map +1 -0
- package/dist/src/factories/EventFactory.js +30 -0
- package/dist/src/factories/EventFactory.js.map +1 -0
- package/dist/src/factories/EventNotificationFactory.d.ts +21 -0
- package/dist/src/factories/EventNotificationFactory.d.ts.map +1 -0
- package/dist/src/factories/EventNotificationFactory.js +44 -0
- package/dist/src/factories/EventNotificationFactory.js.map +1 -0
- package/dist/src/factories/EventNotificationTypeFactory.d.ts +11 -0
- package/dist/src/factories/EventNotificationTypeFactory.d.ts.map +1 -0
- package/dist/src/factories/EventNotificationTypeFactory.js +25 -0
- package/dist/src/factories/EventNotificationTypeFactory.js.map +1 -0
- package/dist/src/factories/PlatformEventTypeFactory.d.ts +10 -0
- package/dist/src/factories/PlatformEventTypeFactory.d.ts.map +1 -0
- package/dist/src/factories/PlatformEventTypeFactory.js +23 -0
- package/dist/src/factories/PlatformEventTypeFactory.js.map +1 -0
- package/dist/src/factories/RecordAnswerFactory.d.ts +17 -0
- package/dist/src/factories/RecordAnswerFactory.d.ts.map +1 -0
- package/dist/src/factories/RecordAnswerFactory.js +95 -0
- package/dist/src/factories/RecordAnswerFactory.js.map +1 -0
- package/dist/src/factories/RecordCategoryFactory.d.ts +11 -0
- package/dist/src/factories/RecordCategoryFactory.d.ts.map +1 -0
- package/dist/src/factories/RecordCategoryFactory.js +23 -0
- package/dist/src/factories/RecordCategoryFactory.js.map +1 -0
- package/dist/src/factories/RecordFactory.d.ts +7 -6
- package/dist/src/factories/RecordFactory.d.ts.map +1 -1
- package/dist/src/factories/RecordFactory.js +10 -4
- package/dist/src/factories/RecordFactory.js.map +1 -1
- package/dist/src/factories/RegistrationPeriodFactory.d.ts +1 -0
- package/dist/src/factories/RegistrationPeriodFactory.d.ts.map +1 -1
- package/dist/src/factories/RegistrationPeriodFactory.js +2 -0
- package/dist/src/factories/RegistrationPeriodFactory.js.map +1 -1
- package/dist/src/factories/index.d.ts +7 -0
- package/dist/src/factories/index.d.ts.map +1 -1
- package/dist/src/factories/index.js +7 -0
- package/dist/src/factories/index.js.map +1 -1
- package/dist/src/helpers/DNSValidator.d.ts.map +1 -1
- package/dist/src/helpers/DNSValidator.js +57 -55
- package/dist/src/helpers/DNSValidator.js.map +1 -1
- package/dist/src/helpers/EmailBuilder.d.ts.map +1 -1
- package/dist/src/helpers/EmailBuilder.js +2 -1
- package/dist/src/helpers/EmailBuilder.js.map +1 -1
- package/dist/src/migrations/1741954610-event-notifications-accepted-record-answers.sql +2 -0
- package/dist/src/migrations/1742393831-default-template-partially-accepted-event-notification.sql +2 -0
- package/dist/src/migrations/1742579832-audit-log-longer-object-size.sql +3 -0
- package/dist/src/models/EventNotification.d.ts +4 -0
- package/dist/src/models/EventNotification.d.ts.map +1 -1
- package/dist/src/models/EventNotification.js +7 -0
- package/dist/src/models/EventNotification.js.map +1 -1
- package/dist/src/models/Organization.d.ts +1 -0
- package/dist/src/models/Organization.d.ts.map +1 -1
- package/dist/src/models/Organization.js +13 -4
- package/dist/src/models/Organization.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/factories/EmailTemplateFactory.ts +47 -0
- package/src/factories/EventFactory.ts +31 -0
- package/src/factories/EventNotificationFactory.ts +51 -0
- package/src/factories/EventNotificationTypeFactory.ts +26 -0
- package/src/factories/PlatformEventTypeFactory.ts +23 -0
- package/src/factories/RecordAnswerFactory.ts +113 -0
- package/src/factories/RecordCategoryFactory.ts +23 -0
- package/src/factories/RecordFactory.ts +14 -8
- package/src/factories/RegistrationPeriodFactory.ts +2 -0
- package/src/factories/index.ts +7 -0
- package/src/helpers/DNSValidator.ts +62 -56
- package/src/helpers/EmailBuilder.ts +2 -1
- package/src/migrations/1741954610-event-notifications-accepted-record-answers.sql +2 -0
- package/src/migrations/1742393831-default-template-partially-accepted-event-notification.sql +2 -0
- package/src/migrations/1742579832-audit-log-longer-object-size.sql +3 -0
- package/src/models/EventNotification.ts +6 -0
- package/src/models/Organization.ts +15 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.ts","../src/factories/addressfactory.ts","../src/factories/balanceitemfactory.ts","../src/factories/emergencycontactfactory.ts","../src/factories/groupfactory.ts","../src/factories/memberfactory.ts","../src/factories/memberresponsibilityrecordfactory.ts","../src/factories/organizationfactory.ts","../src/factories/organizationregistrationperiodfactory.ts","../src/factories/organizationtagfactory.ts","../src/factories/parentfactory.ts","../src/factories/platformresponsibilityfactory.ts","../src/factories/recordfactory.ts","../src/factories/registercodefactory.ts","../src/factories/registrationfactory.ts","../src/factories/registrationperiodfactory.ts","../src/factories/userfactory.ts","../src/factories/webshopfactory.ts","../src/factories/index.ts","../src/helpers/dnsvalidator.ts","../src/helpers/emailbuilder.ts","../src/helpers/groupbuilder.ts","../src/helpers/handlebars.ts","../src/helpers/membermerger.test.ts","../src/helpers/membermerger.ts","../src/helpers/ratelimiter.ts","../src/helpers/webshopcounter.ts","../src/migrations/1605262045-import-postcodes.ts","../src/migrations/1605262046-import-postcodes-nl.ts","../src/models/auditlog.ts","../src/models/balanceitem.ts","../src/models/balanceitempayment.ts","../src/models/buckaroopayment.ts","../src/models/cachedbalance.ts","../src/models/document.ts","../src/models/documenttemplate.ts","../src/models/email.test.ts","../src/models/email.ts","../src/models/emailrecipient.ts","../src/models/emailtemplate.ts","../src/models/emailverificationcode.ts","../src/models/event.ts","../src/models/eventnotification.ts","../src/models/group.ts","../src/models/image.ts","../src/models/member.ts","../src/models/memberplatformmembership.ts","../src/models/memberresponsibilityrecord.ts","../src/models/memberuser.ts","../src/models/mergedmember.ts","../src/models/molliepayment.ts","../src/models/mollietoken.ts","../src/models/onetimetoken.ts","../src/models/order.ts","../src/models/organization.ts","../src/models/organizationregistrationperiod.ts","../src/models/passwordtoken.ts","../src/models/payconiqpayment.ts","../src/models/payment.ts","../src/models/platform.test.ts","../src/models/platform.ts","../src/models/registercode.ts","../src/models/registration.ts","../src/models/registrationperiod.ts","../src/models/stcredit.ts","../src/models/stinvoice.ts","../src/models/stpackage.ts","../src/models/stpendinginvoice.ts","../src/models/stripeaccount.ts","../src/models/stripecheckoutsession.ts","../src/models/stripepaymentintent.ts","../src/models/ticket.ts","../src/models/token.test.ts","../src/models/token.ts","../src/models/usedregistercode.ts","../src/models/user.ts","../src/models/userpermissions.ts","../src/models/webshop.ts","../src/models/webshopdiscountcode.ts","../src/models/index.ts","../src/models/addresses/city.ts","../src/models/addresses/postalcode.test.ts","../src/models/addresses/postalcode.ts","../src/models/addresses/province.ts","../src/models/addresses/street.ts","../src/structures/organizationservermetadata.ts","../tests/jest.global.setup.ts","../tests/jest.setup.ts","../../../../environment.d.ts","../../../../jest-extended.d.ts","../../../stamhoofd.d.ts"],"version":"5.6.2"}
|
|
1
|
+
{"root":["../src/index.ts","../src/factories/addressfactory.ts","../src/factories/balanceitemfactory.ts","../src/factories/emailtemplatefactory.ts","../src/factories/emergencycontactfactory.ts","../src/factories/eventfactory.ts","../src/factories/eventnotificationfactory.ts","../src/factories/eventnotificationtypefactory.ts","../src/factories/groupfactory.ts","../src/factories/memberfactory.ts","../src/factories/memberresponsibilityrecordfactory.ts","../src/factories/organizationfactory.ts","../src/factories/organizationregistrationperiodfactory.ts","../src/factories/organizationtagfactory.ts","../src/factories/parentfactory.ts","../src/factories/platformeventtypefactory.ts","../src/factories/platformresponsibilityfactory.ts","../src/factories/recordanswerfactory.ts","../src/factories/recordcategoryfactory.ts","../src/factories/recordfactory.ts","../src/factories/registercodefactory.ts","../src/factories/registrationfactory.ts","../src/factories/registrationperiodfactory.ts","../src/factories/userfactory.ts","../src/factories/webshopfactory.ts","../src/factories/index.ts","../src/helpers/dnsvalidator.ts","../src/helpers/emailbuilder.ts","../src/helpers/groupbuilder.ts","../src/helpers/handlebars.ts","../src/helpers/membermerger.test.ts","../src/helpers/membermerger.ts","../src/helpers/ratelimiter.ts","../src/helpers/webshopcounter.ts","../src/migrations/1605262045-import-postcodes.ts","../src/migrations/1605262046-import-postcodes-nl.ts","../src/models/auditlog.ts","../src/models/balanceitem.ts","../src/models/balanceitempayment.ts","../src/models/buckaroopayment.ts","../src/models/cachedbalance.ts","../src/models/document.ts","../src/models/documenttemplate.ts","../src/models/email.test.ts","../src/models/email.ts","../src/models/emailrecipient.ts","../src/models/emailtemplate.ts","../src/models/emailverificationcode.ts","../src/models/event.ts","../src/models/eventnotification.ts","../src/models/group.ts","../src/models/image.ts","../src/models/member.ts","../src/models/memberplatformmembership.ts","../src/models/memberresponsibilityrecord.ts","../src/models/memberuser.ts","../src/models/mergedmember.ts","../src/models/molliepayment.ts","../src/models/mollietoken.ts","../src/models/onetimetoken.ts","../src/models/order.ts","../src/models/organization.ts","../src/models/organizationregistrationperiod.ts","../src/models/passwordtoken.ts","../src/models/payconiqpayment.ts","../src/models/payment.ts","../src/models/platform.test.ts","../src/models/platform.ts","../src/models/registercode.ts","../src/models/registration.ts","../src/models/registrationperiod.ts","../src/models/stcredit.ts","../src/models/stinvoice.ts","../src/models/stpackage.ts","../src/models/stpendinginvoice.ts","../src/models/stripeaccount.ts","../src/models/stripecheckoutsession.ts","../src/models/stripepaymentintent.ts","../src/models/ticket.ts","../src/models/token.test.ts","../src/models/token.ts","../src/models/usedregistercode.ts","../src/models/user.ts","../src/models/userpermissions.ts","../src/models/webshop.ts","../src/models/webshopdiscountcode.ts","../src/models/index.ts","../src/models/addresses/city.ts","../src/models/addresses/postalcode.test.ts","../src/models/addresses/postalcode.ts","../src/models/addresses/province.ts","../src/models/addresses/street.ts","../src/structures/organizationservermetadata.ts","../tests/jest.global.setup.ts","../tests/jest.setup.ts","../../../../environment.d.ts","../../../../jest-extended.d.ts","../../../stamhoofd.d.ts"],"version":"5.6.2"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stamhoofd/models",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.80.0",
|
|
4
4
|
"main": "./dist/src/index.js",
|
|
5
5
|
"types": "./dist/src/index.d.ts",
|
|
6
6
|
"license": "UNLICENCED",
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "252faf1dbd8ebdd8469810e9c51e510d93f21fc2"
|
|
34
34
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Factory } from '@simonbackx/simple-database';
|
|
2
|
+
|
|
3
|
+
import { EmailTemplate } from '../models';
|
|
4
|
+
import { Organization } from '../models/Organization';
|
|
5
|
+
import { EmailTemplateType, EmailTemplate as EmailTemplateStruct } from '@stamhoofd/structures';
|
|
6
|
+
|
|
7
|
+
class Options {
|
|
8
|
+
organization?: Organization;
|
|
9
|
+
groupId?: string;
|
|
10
|
+
webshopId?: string;
|
|
11
|
+
type: EmailTemplateType;
|
|
12
|
+
|
|
13
|
+
subject?: string;
|
|
14
|
+
html?: string;
|
|
15
|
+
text?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class EmailTemplateFactory extends Factory<Options, EmailTemplate> {
|
|
19
|
+
async create(): Promise<EmailTemplate> {
|
|
20
|
+
const template = new EmailTemplate();
|
|
21
|
+
|
|
22
|
+
template.organizationId = this.options.organization?.id ?? null;
|
|
23
|
+
template.groupId = this.options.groupId ?? null;
|
|
24
|
+
template.webshopId = this.options.webshopId ?? null;
|
|
25
|
+
template.type = this.options.type;
|
|
26
|
+
|
|
27
|
+
template.subject = this.options.subject ?? this.options.type;
|
|
28
|
+
template.json = {};
|
|
29
|
+
template.html = '';
|
|
30
|
+
template.text = '';
|
|
31
|
+
|
|
32
|
+
if (this.options.html || this.options.text) {
|
|
33
|
+
template.html = this.options.html ?? '<p></p>';
|
|
34
|
+
template.text = this.options.text ?? 'Text';
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// Automatically add all replacements in our template email
|
|
38
|
+
for (const replacement of EmailTemplateStruct.getSupportedReplacementsForType(this.options.type)) {
|
|
39
|
+
template.html += `<p>${replacement.token}: {{${replacement.token}}}</p>`;
|
|
40
|
+
template.text += `${replacement.token}: {{${replacement.token}}}\n`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
await template.save();
|
|
45
|
+
return template;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Factory } from '@simonbackx/simple-database';
|
|
2
|
+
import { EventMeta } from '@stamhoofd/structures';
|
|
3
|
+
|
|
4
|
+
import { Event } from '../models/Event';
|
|
5
|
+
import { Organization } from '../models/Organization';
|
|
6
|
+
import { PlatformEventTypeFactory } from './PlatformEventTypeFactory';
|
|
7
|
+
|
|
8
|
+
class Options {
|
|
9
|
+
organization?: Organization;
|
|
10
|
+
name?: string;
|
|
11
|
+
meta?: EventMeta;
|
|
12
|
+
startDate?: Date;
|
|
13
|
+
endDate?: Date;
|
|
14
|
+
typeId?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class EventFactory extends Factory<Options, Event> {
|
|
18
|
+
async create(): Promise<Event> {
|
|
19
|
+
const event = new Event();
|
|
20
|
+
|
|
21
|
+
event.organizationId = this.options.organization?.id ?? null;
|
|
22
|
+
event.typeId = this.options.typeId ?? (await new PlatformEventTypeFactory({}).create()).id;
|
|
23
|
+
event.startDate = this.options.startDate ?? new Date(Date.now() + 5 * 24 * 60 * 60 * 1000);
|
|
24
|
+
event.endDate = this.options.endDate ?? new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
|
|
25
|
+
event.name = this.options.name ?? 'Event ' + (new Date().getTime() + Math.floor(Math.random() * 999999));
|
|
26
|
+
event.meta = this.options.meta ?? EventMeta.create({});
|
|
27
|
+
|
|
28
|
+
await event.save();
|
|
29
|
+
return event;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Factory } from '@simonbackx/simple-database';
|
|
2
|
+
import { EventNotificationStatus, RecordAnswer } from '@stamhoofd/structures';
|
|
3
|
+
|
|
4
|
+
import { EventNotification, User } from '../models';
|
|
5
|
+
import { Event } from '../models/Event';
|
|
6
|
+
import { Organization } from '../models/Organization';
|
|
7
|
+
import { EventFactory } from './EventFactory';
|
|
8
|
+
import { EventNotificationTypeFactory } from './EventNotificationTypeFactory';
|
|
9
|
+
|
|
10
|
+
class Options {
|
|
11
|
+
organization: Organization;
|
|
12
|
+
events?: Event[];
|
|
13
|
+
typeId?: string;
|
|
14
|
+
status?: EventNotificationStatus;
|
|
15
|
+
feedbackText?: string;
|
|
16
|
+
periodId?: string;
|
|
17
|
+
recordAnswers?: Map<string, RecordAnswer>;
|
|
18
|
+
acceptedRecordAnswers?: Map<string, RecordAnswer>;
|
|
19
|
+
submittedBy?: User | null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class EventNotificationFactory extends Factory<Options, EventNotification> {
|
|
23
|
+
async create(): Promise<EventNotification> {
|
|
24
|
+
const eventNotification = new EventNotification();
|
|
25
|
+
|
|
26
|
+
eventNotification.organizationId = this.options.organization.id;
|
|
27
|
+
eventNotification.typeId = this.options.typeId ?? (await new EventNotificationTypeFactory({}).create()).id;
|
|
28
|
+
eventNotification.status = this.options.status ?? EventNotificationStatus.Draft;
|
|
29
|
+
eventNotification.createdBy = null;
|
|
30
|
+
eventNotification.feedbackText = this.options.feedbackText ?? null;
|
|
31
|
+
|
|
32
|
+
const events = this.options.events ?? [await new EventFactory({ organization: this.options.organization }).create()];
|
|
33
|
+
|
|
34
|
+
eventNotification.startDate = events[0].startDate;
|
|
35
|
+
eventNotification.endDate = events[0].endDate;
|
|
36
|
+
eventNotification.periodId = this.options.periodId ?? this.options.organization.periodId;
|
|
37
|
+
|
|
38
|
+
// Set record answers
|
|
39
|
+
eventNotification.recordAnswers = this.options.recordAnswers ?? new Map();
|
|
40
|
+
eventNotification.acceptedRecordAnswers = this.options.acceptedRecordAnswers ?? new Map();
|
|
41
|
+
|
|
42
|
+
eventNotification.submittedBy = this.options.submittedBy?.id ?? null;
|
|
43
|
+
eventNotification.submittedAt = this.options.submittedBy ? new Date() : null;
|
|
44
|
+
|
|
45
|
+
await eventNotification.save();
|
|
46
|
+
|
|
47
|
+
// Link events
|
|
48
|
+
await EventNotification.events.link(eventNotification, events);
|
|
49
|
+
return eventNotification;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Factory } from '@simonbackx/simple-database';
|
|
2
|
+
import { EventNotificationType, RecordCategory } from '@stamhoofd/structures';
|
|
3
|
+
|
|
4
|
+
import { Platform } from '../models/Platform';
|
|
5
|
+
|
|
6
|
+
class Options {
|
|
7
|
+
title?: string;
|
|
8
|
+
recordCategories?: RecordCategory[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class EventNotificationTypeFactory extends Factory<Options, EventNotificationType> {
|
|
12
|
+
async create(): Promise<EventNotificationType> {
|
|
13
|
+
const eventType = EventNotificationType.create({
|
|
14
|
+
title: this.options.title ?? ('Melding ' + (new Date().getTime() + Math.floor(Math.random() * 999999))),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
eventType.recordCategories = this.options.recordCategories ?? [];
|
|
18
|
+
|
|
19
|
+
// Add to platform
|
|
20
|
+
const platform = await Platform.getForEditing();
|
|
21
|
+
platform.config.eventNotificationTypes.push(eventType);
|
|
22
|
+
await platform.save();
|
|
23
|
+
|
|
24
|
+
return eventType;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Factory } from '@simonbackx/simple-database';
|
|
2
|
+
import { PlatformEventType } from '@stamhoofd/structures';
|
|
3
|
+
|
|
4
|
+
import { Platform } from '../models/Platform';
|
|
5
|
+
|
|
6
|
+
class Options {
|
|
7
|
+
name?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class PlatformEventTypeFactory extends Factory<Options, PlatformEventType> {
|
|
11
|
+
async create(): Promise<PlatformEventType> {
|
|
12
|
+
const eventType = PlatformEventType.create({
|
|
13
|
+
name: this.options.name ?? ('Responsibility ' + (new Date().getTime() + Math.floor(Math.random() * 999999))),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Add to platform
|
|
17
|
+
const platform = await Platform.getForEditing();
|
|
18
|
+
platform.config.eventTypes.push(eventType);
|
|
19
|
+
await platform.save();
|
|
20
|
+
|
|
21
|
+
return eventType;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Factory } from '@simonbackx/simple-database';
|
|
2
|
+
import { File, Image, RecordAddressAnswer, RecordAnswer, RecordCategory, RecordCheckboxAnswer, RecordChooseOneAnswer, RecordDateAnswer, RecordFileAnswer, RecordImageAnswer, RecordIntegerAnswer, RecordMultipleChoiceAnswer, RecordPriceAnswer, RecordSettings, RecordTextAnswer, RecordType } from '@stamhoofd/structures';
|
|
3
|
+
import { AddressFactory } from './AddressFactory';
|
|
4
|
+
|
|
5
|
+
type Options = ({
|
|
6
|
+
records: RecordSettings[];
|
|
7
|
+
} | {
|
|
8
|
+
recordCategories: RecordCategory[];
|
|
9
|
+
}) & {
|
|
10
|
+
/**
|
|
11
|
+
* Defaults to true
|
|
12
|
+
*/
|
|
13
|
+
complete?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export class RecordAnswerFactory extends Factory<Options, Map<string, RecordAnswer>> {
|
|
17
|
+
async create(): Promise<Map<string, RecordAnswer>> {
|
|
18
|
+
const records = 'records' in this.options ? this.options.records : this.options.recordCategories.flatMap(c => c.getAllRecords());
|
|
19
|
+
|
|
20
|
+
const map: Map<string, RecordAnswer> = new Map();
|
|
21
|
+
|
|
22
|
+
for (const record of records) {
|
|
23
|
+
const answer = RecordAnswer.createDefaultAnswer(record);
|
|
24
|
+
|
|
25
|
+
if (this.options.complete !== false) {
|
|
26
|
+
// Make sure it is filled in
|
|
27
|
+
answer.markReviewed();
|
|
28
|
+
|
|
29
|
+
switch (true) {
|
|
30
|
+
case answer instanceof RecordCheckboxAnswer: {
|
|
31
|
+
// If it is a checkbox, set the first one to true
|
|
32
|
+
answer.selected = true;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
case answer instanceof RecordTextAnswer: {
|
|
36
|
+
answer.value = 'Test ' + Math.floor(Math.random() * 100000);
|
|
37
|
+
|
|
38
|
+
switch (record.type) {
|
|
39
|
+
case RecordType.Phone:{
|
|
40
|
+
answer.value = '+32 477 77 77 77';
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
case RecordType.Email: {
|
|
44
|
+
answer.value = 'example@example.domain';
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case RecordType.Textarea: {
|
|
48
|
+
answer.value = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nVivamus lacinia odio vitae vestibulum.';
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
case answer instanceof RecordMultipleChoiceAnswer: {
|
|
56
|
+
// If it is a multiple choice, select all
|
|
57
|
+
answer.selectedChoices = record.choices.map(c => c.clone());
|
|
58
|
+
break;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
case answer instanceof RecordChooseOneAnswer: {
|
|
62
|
+
// Select first
|
|
63
|
+
answer.selectedChoice = record.choices[0]?.clone() ?? null;
|
|
64
|
+
break;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
case answer instanceof RecordAddressAnswer: {
|
|
68
|
+
answer.address = await new AddressFactory({}).create();
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
case answer instanceof RecordDateAnswer: {
|
|
73
|
+
answer.dateValue = new Date();
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
case answer instanceof RecordPriceAnswer: {
|
|
78
|
+
answer.value = 1234;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
case answer instanceof RecordImageAnswer: {
|
|
83
|
+
answer.image = Image.create({});
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
case answer instanceof RecordIntegerAnswer: {
|
|
88
|
+
answer.value = 5;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
case answer instanceof RecordFileAnswer: {
|
|
93
|
+
answer.file = new File({
|
|
94
|
+
id: 'example-id',
|
|
95
|
+
server: 'https://example.domain',
|
|
96
|
+
path: 'example/path/to/file',
|
|
97
|
+
size: 1234,
|
|
98
|
+
name: 'example.txt',
|
|
99
|
+
isPrivate: false,
|
|
100
|
+
signedUrl: null,
|
|
101
|
+
signature: null,
|
|
102
|
+
});
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
map.set(record.id, answer);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return map;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Factory } from '@simonbackx/simple-database';
|
|
2
|
+
import { RecordCategory, RecordSettings, RecordType } from '@stamhoofd/structures';
|
|
3
|
+
import { RecordFactory, RecordOptions } from './RecordFactory';
|
|
4
|
+
|
|
5
|
+
class Options {
|
|
6
|
+
records: RecordOptions[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class RecordCategoryFactory extends Factory<Options, RecordCategory> {
|
|
10
|
+
async create(): Promise<RecordCategory> {
|
|
11
|
+
const records: RecordSettings[] = [];
|
|
12
|
+
for (const record of this.options.records) {
|
|
13
|
+
records.push(
|
|
14
|
+
await new RecordFactory(record).create(),
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return RecordCategory.create({
|
|
19
|
+
name: 'Record category ' + Math.floor(Math.random() * 10000),
|
|
20
|
+
records,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { Factory } from '@simonbackx/simple-database';
|
|
2
|
-
import {
|
|
2
|
+
import { RecordSettings, RecordType } from '@stamhoofd/structures';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
export class RecordOptions {
|
|
5
|
+
type: RecordType;
|
|
6
|
+
required?: boolean;
|
|
7
|
+
}
|
|
5
8
|
|
|
6
|
-
export class RecordFactory extends Factory<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
export class RecordFactory extends Factory<RecordOptions, RecordSettings> {
|
|
10
|
+
create(): Promise<RecordSettings> {
|
|
11
|
+
return Promise.resolve(
|
|
12
|
+
RecordSettings.create({
|
|
13
|
+
name: 'Record name ' + Math.floor(Math.random() * 10000),
|
|
14
|
+
type: this.options.type,
|
|
15
|
+
required: this.options.required ?? (this.options.type !== RecordType.Checkbox),
|
|
16
|
+
}),
|
|
17
|
+
);
|
|
12
18
|
}
|
|
13
19
|
}
|
|
@@ -7,6 +7,7 @@ class Options {
|
|
|
7
7
|
startDate?: Date;
|
|
8
8
|
endDate?: Date;
|
|
9
9
|
previousPeriodId?: string;
|
|
10
|
+
locked?: boolean;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export class RegistrationPeriodFactory extends Factory<Options, RegistrationPeriod> {
|
|
@@ -20,6 +21,7 @@ export class RegistrationPeriodFactory extends Factory<Options, RegistrationPeri
|
|
|
20
21
|
period.previousPeriodId = this.options.previousPeriodId;
|
|
21
22
|
}
|
|
22
23
|
period.settings = RegistrationPeriodSettings.create({});
|
|
24
|
+
period.locked = this.options.locked ?? false;
|
|
23
25
|
|
|
24
26
|
await period.save();
|
|
25
27
|
return period;
|
package/src/factories/index.ts
CHANGED
|
@@ -15,3 +15,10 @@ export * from './OrganizationTagFactory';
|
|
|
15
15
|
export * from './OrganizationRegistrationPeriodFactory';
|
|
16
16
|
export * from './MemberResponsibilityRecordFactory';
|
|
17
17
|
export * from './PlatformResponsibilityFactory';
|
|
18
|
+
export * from './PlatformEventTypeFactory';
|
|
19
|
+
export * from './EventFactory';
|
|
20
|
+
export * from './EventNotificationTypeFactory';
|
|
21
|
+
export * from './EventNotificationFactory';
|
|
22
|
+
export * from './EmailTemplateFactory';
|
|
23
|
+
export * from './RecordCategoryFactory';
|
|
24
|
+
export * from './RecordAnswerFactory';
|
|
@@ -20,16 +20,19 @@ export async function validateDNSRecords(dnsRecords: DNSRecord[], didRetry = fal
|
|
|
20
20
|
const addresses: string[] = await resolver.resolveCname(record.name.substr(0, record.name.length - 1));
|
|
21
21
|
record.errors = null;
|
|
22
22
|
|
|
23
|
-
if (addresses.length
|
|
23
|
+
if (addresses.length === 0) {
|
|
24
24
|
record.status = DNSRecordStatus.Pending;
|
|
25
|
-
allValid = false;
|
|
26
|
-
hasAllNonTXT = false;
|
|
27
25
|
|
|
28
|
-
record.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
if (!record.optional) {
|
|
27
|
+
allValid = false;
|
|
28
|
+
hasAllNonTXT = false;
|
|
29
|
+
|
|
30
|
+
record.errors = new SimpleErrors(new SimpleError({
|
|
31
|
+
code: 'not_found',
|
|
32
|
+
message: '',
|
|
33
|
+
human: 'We konden de CNAME-record ' + record.name + ' nog niet vinden. Hou er rekening mee dat het even (tot 24u) kan duren voor we deze kunnen zien.',
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
33
36
|
}
|
|
34
37
|
else if (addresses.length > 1) {
|
|
35
38
|
record.status = DNSRecordStatus.Failed;
|
|
@@ -39,7 +42,7 @@ export async function validateDNSRecords(dnsRecords: DNSRecord[], didRetry = fal
|
|
|
39
42
|
record.errors = new SimpleErrors(new SimpleError({
|
|
40
43
|
code: 'too_many_fields',
|
|
41
44
|
message: '',
|
|
42
|
-
human: 'Er zijn meerdere CNAME records ingesteld voor ' + record.name + ', kijk na of je er geen moet verwijderen of per ongeluk
|
|
45
|
+
human: 'Er zijn meerdere CNAME records ingesteld voor ' + record.name + ', kijk na of je er geen moet verwijderen of per ongeluk meerdere hebt aangemaakt',
|
|
43
46
|
}));
|
|
44
47
|
}
|
|
45
48
|
else {
|
|
@@ -48,14 +51,17 @@ export async function validateDNSRecords(dnsRecords: DNSRecord[], didRetry = fal
|
|
|
48
51
|
}
|
|
49
52
|
else {
|
|
50
53
|
record.status = DNSRecordStatus.Failed;
|
|
51
|
-
allValid = false;
|
|
52
|
-
hasAllNonTXT = false;
|
|
53
54
|
|
|
54
|
-
record.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
if (!record.optional) {
|
|
56
|
+
allValid = false;
|
|
57
|
+
hasAllNonTXT = false;
|
|
58
|
+
|
|
59
|
+
record.errors = new SimpleErrors(new SimpleError({
|
|
60
|
+
code: 'wrong_value',
|
|
61
|
+
message: '',
|
|
62
|
+
human: 'Er is een andere waarde ingesteld voor de CNAME-record ' + record.name + ', kijk na of je geen typfout hebt gemaakt. Gevonden: ' + addresses[0] + '.',
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
67
|
|
|
@@ -67,15 +73,18 @@ export async function validateDNSRecords(dnsRecords: DNSRecord[], didRetry = fal
|
|
|
67
73
|
|
|
68
74
|
record.errors = null;
|
|
69
75
|
|
|
70
|
-
if (records.length
|
|
76
|
+
if (records.length === 0) {
|
|
71
77
|
record.status = DNSRecordStatus.Pending;
|
|
72
|
-
allValid = false;
|
|
73
78
|
|
|
74
|
-
record.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
if (!record.optional) {
|
|
80
|
+
allValid = false;
|
|
81
|
+
|
|
82
|
+
record.errors = new SimpleErrors(new SimpleError({
|
|
83
|
+
code: 'not_found',
|
|
84
|
+
message: '',
|
|
85
|
+
human: 'We konden de TXT-record ' + record.name + ' nog niet vinden. Hou er rekening mee dat het even (tot 24u) kan duren voor we deze kunnen zien.',
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
79
88
|
}
|
|
80
89
|
else if (records.length > 1) {
|
|
81
90
|
record.status = DNSRecordStatus.Failed;
|
|
@@ -89,29 +98,20 @@ export async function validateDNSRecords(dnsRecords: DNSRecord[], didRetry = fal
|
|
|
89
98
|
else {
|
|
90
99
|
const val = records[0].join('').trim();
|
|
91
100
|
if (val === record.value.trim()) {
|
|
92
|
-
/* if (records[0].length > 1 && val.length <= 255) {
|
|
93
|
-
// Split was not needed and is not supported by SES
|
|
94
|
-
record.status = DNSRecordStatus.Failed
|
|
95
|
-
allValid = false
|
|
96
|
-
|
|
97
|
-
record.errors = new SimpleErrors(new SimpleError({
|
|
98
|
-
code: "wrong_value",
|
|
99
|
-
message: "",
|
|
100
|
-
human: "De waarde komt overeen maar is op één of andere manier opgesplitst in meerdere stukken, terwijl dat niet nodig is. Dit wordt niet ondersteund door onze e-mailprovider. Contacteer ons als je de oorzaak niet kan achterhalen."
|
|
101
|
-
}))
|
|
102
|
-
} else { */
|
|
103
101
|
record.status = DNSRecordStatus.Valid;
|
|
104
|
-
// }
|
|
105
102
|
}
|
|
106
103
|
else {
|
|
107
104
|
record.status = DNSRecordStatus.Failed;
|
|
108
|
-
allValid = false;
|
|
109
105
|
|
|
110
|
-
record.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
106
|
+
if (!record.optional) {
|
|
107
|
+
allValid = false;
|
|
108
|
+
|
|
109
|
+
record.errors = new SimpleErrors(new SimpleError({
|
|
110
|
+
code: 'wrong_value',
|
|
111
|
+
message: '',
|
|
112
|
+
human: 'Er is een andere waarde ingesteld voor de TXT-record ' + record.name + ', kijk na of je geen typfout hebt gemaakt. Gevonden: ' + records[0].join(''),
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
break;
|
|
@@ -121,26 +121,32 @@ export async function validateDNSRecords(dnsRecords: DNSRecord[], didRetry = fal
|
|
|
121
121
|
catch (e) {
|
|
122
122
|
record.status = DNSRecordStatus.Pending;
|
|
123
123
|
|
|
124
|
-
if (e.code && (e.code
|
|
125
|
-
record.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
124
|
+
if (e.code && (e.code === 'ENOTFOUND' || e.code === 'ENODATA')) {
|
|
125
|
+
if (!record.optional) {
|
|
126
|
+
record.errors = new SimpleErrors(new SimpleError({
|
|
127
|
+
code: 'not_found',
|
|
128
|
+
message: '',
|
|
129
|
+
human: 'We konden de record ' + record.name + ' nog niet vinden. Hou er rekening mee dat het even (tot 24u) kan duren voor we deze kunnen zien.',
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
130
132
|
}
|
|
131
133
|
else {
|
|
132
134
|
console.error(e);
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
if (!record.optional) {
|
|
136
|
+
record.errors = new SimpleErrors(new SimpleError({
|
|
137
|
+
code: 'not_found',
|
|
138
|
+
message: '',
|
|
139
|
+
human: 'Er ging iets mis. Deze record lijkt niet goed ingesteld te zijn.',
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
139
142
|
}
|
|
140
|
-
allValid = false;
|
|
141
143
|
|
|
142
|
-
if (record.
|
|
143
|
-
|
|
144
|
+
if (!record.optional) {
|
|
145
|
+
allValid = false;
|
|
146
|
+
|
|
147
|
+
if (record.type !== DNSRecordType.TXT) {
|
|
148
|
+
hasAllNonTXT = false;
|
|
149
|
+
}
|
|
144
150
|
}
|
|
145
151
|
}
|
|
146
152
|
}
|
|
@@ -209,6 +209,7 @@ async function getEmailBuilderForTemplate(organization: Organization | null, opt
|
|
|
209
209
|
});
|
|
210
210
|
|
|
211
211
|
if (!template) {
|
|
212
|
+
console.warn('No email template found for ' + options.template.type);
|
|
212
213
|
return undefined;
|
|
213
214
|
}
|
|
214
215
|
|
|
@@ -318,7 +319,7 @@ export async function getEmailBuilder(organization: Organization | null, email:
|
|
|
318
319
|
|
|
319
320
|
// Override headers
|
|
320
321
|
recipient.headers = {
|
|
321
|
-
'List-Unsubscribe': `<${unsubscribeUrl}>`,
|
|
322
|
+
'List-Unsubscribe': STAMHOOFD.domains.defaultBroadcastEmail !== undefined ? '<mailto:unsubscribe+' + unsubscribe.id + '@' + STAMHOOFD.domains.defaultBroadcastEmail![''] + `>, <${unsubscribeUrl}>` : `<${unsubscribeUrl}>`,
|
|
322
323
|
'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click',
|
|
323
324
|
};
|
|
324
325
|
cleaned.push(recipient);
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
INSERT INTO `email_templates` (`id`, `subject`, `groupId`, `webshopId`, `organizationId`, `type`, `text`, `html`, `json`, `updatedAt`, `createdAt`) VALUES
|
|
2
|
+
('7b28fe12-d06e-49d0-9acf-102a1873253a', 'Kampmelding voor {{eventName}} ({{dateRange}}) werd voorlopig goedgekeurd', NULL, NULL, NULL, 'EventNotificationPartiallyAccepted', '{{greeting}}Goed nieuws! Jullie kampmelding voor {{eventName}} ({{dateRange}}) van {{organizationName}} werd voorlopig goedgekeurd. Deze werd ingediend door {{submitterName}}.\n\n \n \n \n \n Kampmelding bekijken\n \n \n \n \n\nOpmerkingen{{feedbackText}}', '<!DOCTYPE html>\n<html>\n\n<head>\n<meta charset=\"utf-8\" />\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\" />\n<title>Kampmelding voor {{eventName}} ({{dateRange}}) werd voorlopig goedgekeurd</title>\n<style type=\"text/css\">body {\n color: #000716;\n color: var(--color-dark, #000716);\n font-family: -apple-system-body, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n font-size: 12pt;\n line-height: 1.4;\n}\n\np {\n margin: 0;\n padding: 0;\n line-height: 1.4;\n}\n\np.description {\n color: var(--color-gray-4, #5e5e5e);\n}\np.description a, p.description a:link, p.description a:visited, p.description a:active, p.description a:hover {\n text-decoration: underline;\n color: var(--color-gray-4, #5e5e5e);\n}\n\nstrong {\n font-weight: bold;\n}\n\nem {\n font-style: italic;\n}\n\nh1 {\n font-size: 30px;\n font-weight: bold;\n line-height: 1.2;\n margin: 0;\n padding: 0;\n}\n@media (max-width: 350px) {\n h1 {\n font-size: 24px;\n }\n}\n\nh2 {\n font-size: 20px;\n line-height: 1.2;\n font-weight: bold;\n margin: 0;\n padding: 0;\n}\n\nh3 {\n font-size: 16px;\n line-height: 1.2;\n font-weight: bold;\n margin: 0;\n padding: 0;\n}\n\nh4 {\n line-height: 1.2;\n font-weight: 500;\n margin: 0;\n padding: 0;\n}\n\nol, ul {\n list-style-position: outside;\n padding-left: 30px;\n}\n\nhr {\n height: 1px;\n background: var(--color-border, var(--color-gray-2, #dcdcdc));\n border-radius: 1px;\n padding: 0;\n margin: 20px 0;\n outline: none;\n border: 0;\n}\n\n.button {\n touch-action: inherit;\n user-select: auto;\n cursor: pointer;\n display: inline-block !important;\n line-height: 42px;\n font-size: 16px;\n font-weight: bold;\n}\n.button:active {\n transform: none;\n}\n\nimg {\n max-width: 100%;\n height: auto;\n}\n\na, a:link, a:visited, a:active, a:hover {\n text-decoration: underline;\n color: blue;\n}\n\n.email-data-table {\n width: 100%;\n border-collapse: collapse;\n}\n.email-data-table th, .email-data-table td {\n text-align: left;\n padding: 10px 10px 10px 0;\n border-bottom: 1px solid var(--color-border, var(--color-gray-2, #dcdcdc));\n vertical-align: middle;\n}\n.email-data-table th:last-child, .email-data-table td:last-child {\n text-align: right;\n padding-right: 0;\n}\n.email-data-table thead {\n font-weight: bold;\n}\n.email-data-table thead th {\n font-size: 10pt;\n}\n.email-data-table h4 ~ p {\n padding-top: 3px;\n opacity: 0.8;\n font-size: 11pt;\n}\n\n.email-style-inline-code {\n font-family: monospace;\n white-space: pre-wrap;\n display: inline-block;\n}\n\n.email-style-description-small {\n font-size: 14px;\n line-height: 1.5;\n font-weight: normal;\n color: var(--color-gray-4, #5e5e5e);\n font-variation-settings: \"opsz\" 19;\n}\n\n.email-style-title-list {\n font-size: 16px;\n line-height: 1.3;\n font-weight: 500;\n}\n.email-style-title-list + p {\n padding-top: 3px;\n}\n\n.email-style-title-prefix-list {\n font-size: 11px;\n line-height: 1.5;\n font-weight: bold;\n color: {{primaryColor}};\n text-transform: uppercase;\n margin-bottom: 3px;\n}\n.email-style-title-prefix-list.error {\n color: #f0153d;\n}\n\n.email-style-price-base, .email-style-discount-price, .email-style-discount-old-price, .email-style-price {\n font-size: 15px;\n line-height: 1.4;\n font-weight: 500;\n font-variant-numeric: tabular-nums;\n}\n.email-style-price-base.disabled, .disabled.email-style-discount-price, .disabled.email-style-discount-old-price, .disabled.email-style-price {\n opacity: 0.6;\n}\n.email-style-price-base.negative, .negative.email-style-discount-price, .negative.email-style-discount-old-price, .negative.email-style-price {\n color: #f0153d;\n}\n\n.email-style-price {\n font-weight: bold;\n color: {{primaryColor}};\n}\n\n.email-style-discount-old-price {\n text-decoration: line-through;\n color: var(--color-gray-4, #5e5e5e);\n}\n\n.email-style-discount-price {\n font-weight: bold;\n color: #ff4747;\n margin-left: 5px;\n}\n\n.pre-wrap {\n white-space: pre-wrap;\n} hr {height: 2px;background: #e7e7e7; border-radius: 1px; padding: 0; margin: 20px 0; outline: none; border: 0;} .button.primary { margin: 0; text-decoration: none; font-size: 16px; font-weight: bold; color: {{primaryColorContrast}}; padding: 0 27px; line-height: 42px; background: {{primaryColor}}; text-align: center; border-radius: 7px; touch-action: manipulation; display: inline-block; transition: 0.2s transform, 0.2s opacity; } .button.primary:active { transform: scale(0.95, 0.95); } .inline-link, .inline-link:link, .inline-link:visited, .inline-link:active, .inline-link:hover { margin: 0; text-decoration: underline; font-size: inherit; font-weight: inherit; color: inherit; touch-action: manipulation; } .inline-link:active { opacity: 0.5; } .description { color: #5e5e5e; } </style>\n</head>\n\n<body>\n<p style=\"margin: 0; padding: 0; line-height: 1.4;\">{{greeting}}</p><p style=\"margin: 0; padding: 0; line-height: 1.4;\"><br></p><p style=\"margin: 0; padding: 0; line-height: 1.4;\">Goed nieuws! Jullie kampmelding voor <strong>{{eventName}}</strong> ({{dateRange}}) van <strong>{{organizationName}}</strong> werd voorlopig goedgekeurd. Deze werd ingediend door {{submitterName}}.</p><p style=\"margin: 0; padding: 0; line-height: 1.4;\"><br></p><div data-type=\"smartButton\" data-id=\"reviewUrl\"><table width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"margin: 5px 0;\">\n<tbody><tr>\n <td>\n <table cellspacing=\"0\" cellpadding=\"0\">\n <tbody><tr>\n <td style=\"border-radius: 7px;\" bgcolor=\"{{primaryColor}}\">\n <a class=\"button primary\" href=\"{{reviewUrl}}\" target=\"\" style=\"margin: 0; text-decoration: none; font-size: 16px; font-weight: bold; color: {{primaryColorContrast}}; padding: 0 27px; line-height: 42px; background: {{primaryColor}}; text-align: center; border-radius: 7px; touch-action: manipulation; display: inline-block; transition: 0.2s transform, 0.2s opacity;\">Kampmelding bekijken</a>\n </td>\n </tr>\n </tbody></table>\n </td>\n</tr>\n</tbody></table></div><p style=\"margin: 0; padding: 0; line-height: 1.4;\"><br></p><hr style=\"height: 2px;background: #e7e7e7; border-radius: 1px; padding: 0; margin: 20px 0; outline: none; border: 0;\"><h2 style=\"margin: 0; padding: 0;\">Opmerkingen</h2><p style=\"margin: 0; padding: 0; line-height: 1.4;\"><br></p><div data-type=\"smartVariableBlock\" data-id=\"feedbackText\">{{feedbackText}}</div><p style=\"margin: 0; padding: 0; line-height: 1.4;\"><br></p>\n</body>\n\n</html>', '{\"value\": {\"type\": \"doc\", \"content\": [{\"type\": \"paragraph\", \"content\": [{\"type\": \"smartVariable\", \"attrs\": {\"id\": \"greeting\"}}]}, {\"type\": \"paragraph\"}, {\"type\": \"paragraph\", \"content\": [{\"text\": \"Goed nieuws! Jullie kampmelding voor \", \"type\": \"text\"}, {\"type\": \"smartVariable\", \"attrs\": {\"id\": \"eventName\"}, \"marks\": [{\"type\": \"bold\"}]}, {\"text\": \" (\", \"type\": \"text\"}, {\"type\": \"smartVariable\", \"attrs\": {\"id\": \"dateRange\"}}, {\"text\": \") van \", \"type\": \"text\"}, {\"type\": \"smartVariable\", \"attrs\": {\"id\": \"organizationName\"}, \"marks\": [{\"type\": \"bold\"}]}, {\"text\": \" werd voorlopig goedgekeurd. Deze werd ingediend door \", \"type\": \"text\"}, {\"type\": \"smartVariable\", \"attrs\": {\"id\": \"submitterName\"}}, {\"text\": \".\", \"type\": \"text\"}]}, {\"type\": \"paragraph\"}, {\"type\": \"smartButton\", \"attrs\": {\"id\": \"reviewUrl\"}, \"content\": [{\"text\": \"Kampmelding bekijken\", \"type\": \"text\"}]}, {\"type\": \"paragraph\"}, {\"type\": \"horizontalRule\"}, {\"type\": \"heading\", \"attrs\": {\"level\": 2}, \"content\": [{\"text\": \"Opmerkingen\", \"type\": \"text\"}]}, {\"type\": \"paragraph\"}, {\"type\": \"smartVariableBlock\", \"attrs\": {\"id\": \"feedbackText\"}}, {\"type\": \"paragraph\"}]}, \"version\": 367}', '2025-03-19 14:16:02', '2025-03-19 14:16:02');
|