send or print newsletter preview
This commit is contained in:
parent
5a59a63e4a
commit
5f827fb177
15 changed files with 355 additions and 28 deletions
|
@ -13,7 +13,10 @@ import NewsletterDatesCommandHandler from "../../command/newsletterDatesCommandH
|
||||||
import { SynchronizeNewsletterRecipientsCommand } from "../../command/newsletterRecipientsCommand";
|
import { SynchronizeNewsletterRecipientsCommand } from "../../command/newsletterRecipientsCommand";
|
||||||
import NewsletterRecipientsCommandHandler from "../../command/newsletterRecipientsCommandHandler";
|
import NewsletterRecipientsCommandHandler from "../../command/newsletterRecipientsCommandHandler";
|
||||||
import { NewsletterDatesViewModel } from "../../viewmodel/admin/newsletterDates.models";
|
import { NewsletterDatesViewModel } from "../../viewmodel/admin/newsletterDates.models";
|
||||||
import { NewsletterRecipientsViewModel } from "../../viewmodel/admin/newsletterRecipients.models";
|
import { PdfExport } from "../../helpers/pdfExport";
|
||||||
|
import UserService from "../../service/userService";
|
||||||
|
import { TemplateHelper } from "../../helpers/templateHelper";
|
||||||
|
import MailHelper from "../../helpers/mailHelper";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description get all newsletters
|
* @description get all newsletters
|
||||||
|
@ -113,6 +116,84 @@ export async function getNewsletterPrintoutByIdAndPrint(req: Request, res: Respo
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description create newsletter printout preview by id
|
||||||
|
* @param req {Request} Express req object
|
||||||
|
* @param res {Response} Express res object
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function createNewsletterPrintoutPreviewById(req: Request, res: Response): Promise<any> {
|
||||||
|
let newsletterId = parseInt(req.params.newsletterId);
|
||||||
|
let newsletter = await NewsletterService.getById(newsletterId);
|
||||||
|
let dates = await NewsletterDatesService.getAll(newsletterId);
|
||||||
|
let recipient = await UserService.getById(parseInt(req.userId));
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
title: newsletter.title,
|
||||||
|
description: newsletter.description,
|
||||||
|
newsletterTitle: newsletter.newsletterTitle,
|
||||||
|
newsletterText: newsletter.newsletterText,
|
||||||
|
newsletterSignatur: newsletter.newsletterSignatur,
|
||||||
|
dates: dates.map((d) => ({
|
||||||
|
title: d.diffTitle ?? d.calendar.title,
|
||||||
|
content: d.diffDescription ?? d.calendar.content,
|
||||||
|
starttime: d.calendar.starttime,
|
||||||
|
formattedStarttime: new Date(d.calendar.starttime).toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
}),
|
||||||
|
formattedFullStarttime: new Date(d.calendar.starttime).toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
}),
|
||||||
|
endtime: d.calendar.endtime,
|
||||||
|
formattedEndtime: new Date(d.calendar.endtime).toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
}),
|
||||||
|
formattedFullEndtime: new Date(d.calendar.endtime).toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
}),
|
||||||
|
location: d.calendar.location,
|
||||||
|
})),
|
||||||
|
recipient: {
|
||||||
|
firstname: recipient.firstname,
|
||||||
|
lastname: recipient.lastname,
|
||||||
|
salutation: "none",
|
||||||
|
nameaffix: "",
|
||||||
|
street: "Straße",
|
||||||
|
streetNumber: "Hausnummer",
|
||||||
|
streetNumberAdd: "Adresszusatz",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let pdf = await PdfExport.renderFile({
|
||||||
|
title: "Probedruck Newsletter",
|
||||||
|
template: "newsletter",
|
||||||
|
saveToDisk: false,
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
|
||||||
|
let pdfbuffer = Buffer.from(pdf);
|
||||||
|
|
||||||
|
res.setHeader("Content-Type", "application/pdf");
|
||||||
|
res.setHeader("Content-Length", pdfbuffer.byteLength);
|
||||||
|
res.setHeader("Content-Disposition", "inline; filename=preview.pdf");
|
||||||
|
|
||||||
|
res.send(pdfbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description create newsletter
|
* @description create newsletter
|
||||||
* @param req {Request} Express req object
|
* @param req {Request} Express req object
|
||||||
|
@ -131,7 +212,7 @@ export async function createNewsletter(req: Request, res: Response): Promise<any
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description create newsletter printout by id
|
* @description create newsletter printouts for each member by id
|
||||||
* @param req {Request} Express req object
|
* @param req {Request} Express req object
|
||||||
* @param res {Response} Express res object
|
* @param res {Response} Express res object
|
||||||
* @returns {Promise<*>}
|
* @returns {Promise<*>}
|
||||||
|
@ -151,6 +232,96 @@ export async function createNewsletterPrintoutById(req: Request, res: Response):
|
||||||
res.sendStatus(204);
|
res.sendStatus(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description create newsletter mail preview by id
|
||||||
|
* @param req {Request} Express req object
|
||||||
|
* @param res {Response} Express res object
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function createNewsletterMailPreviewById(req: Request, res: Response): Promise<any> {
|
||||||
|
let newsletterId = parseInt(req.params.newsletterId);
|
||||||
|
let newsletter = await NewsletterService.getById(newsletterId);
|
||||||
|
let dates = await NewsletterDatesService.getAll(newsletterId);
|
||||||
|
let recipient = await UserService.getById(parseInt(req.userId));
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
title: newsletter.title,
|
||||||
|
description: newsletter.description,
|
||||||
|
newsletterTitle: newsletter.newsletterTitle,
|
||||||
|
newsletterText: newsletter.newsletterText,
|
||||||
|
newsletterSignatur: newsletter.newsletterSignatur,
|
||||||
|
dates: dates.map((d) => ({
|
||||||
|
title: d.diffTitle ?? d.calendar.title,
|
||||||
|
content: d.diffDescription ?? d.calendar.content,
|
||||||
|
starttime: d.calendar.starttime,
|
||||||
|
formattedStarttime: new Date(d.calendar.starttime).toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
}),
|
||||||
|
formattedFullStarttime: new Date(d.calendar.starttime).toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
}),
|
||||||
|
endtime: d.calendar.endtime,
|
||||||
|
formattedEndtime: new Date(d.calendar.endtime).toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
}),
|
||||||
|
formattedFullEndtime: new Date(d.calendar.endtime).toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
}),
|
||||||
|
location: d.calendar.location,
|
||||||
|
})),
|
||||||
|
recipient: {
|
||||||
|
firstname: recipient.firstname,
|
||||||
|
lastname: recipient.lastname,
|
||||||
|
salutation: "none",
|
||||||
|
nameaffix: "",
|
||||||
|
street: "Straße",
|
||||||
|
streetNumber: "Hausnummer",
|
||||||
|
streetNumberAdd: "Adresszusatz",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const { body } = await TemplateHelper.renderFileForModule({
|
||||||
|
module: "newsletter",
|
||||||
|
bodyData: data,
|
||||||
|
title: "Probeversand Newsletter",
|
||||||
|
});
|
||||||
|
|
||||||
|
await MailHelper.sendMail(recipient.mail, "Probeversand Newsletter", body);
|
||||||
|
|
||||||
|
res.sendStatus(204);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description send newsletter mail and create printouts by id
|
||||||
|
* @param req {Request} Express req object
|
||||||
|
* @param res {Response} Express res object
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function sendNewsletterById(req: Request, res: Response): Promise<any> {
|
||||||
|
let newsletterId = parseInt(req.params.newsletterId);
|
||||||
|
let newsletter = await NewsletterService.getById(newsletterId);
|
||||||
|
let dates = await NewsletterDatesService.getAll(newsletterId);
|
||||||
|
let recipients = await NewsletterRecipientsService.getAll(newsletterId);
|
||||||
|
|
||||||
|
// attach ics files for date entries to mail
|
||||||
|
|
||||||
|
res.sendStatus(204);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description synchronize newsletter by id
|
* @description synchronize newsletter by id
|
||||||
* @param req {Request} Express req object
|
* @param req {Request} Express req object
|
||||||
|
|
|
@ -40,7 +40,11 @@ export async function printTemplateUsageDemo(req: Request, res: Response): Promi
|
||||||
const scope = req.params.scope as PermissionModule;
|
const scope = req.params.scope as PermissionModule;
|
||||||
|
|
||||||
let demoData = DemoDataHelper.getData(scope);
|
let demoData = DemoDataHelper.getData(scope);
|
||||||
let pdf = await PdfExport.renderFile({ template: scope, saveToDisk: false, data: demoData });
|
let pdf = await PdfExport.renderFile({
|
||||||
|
template: scope,
|
||||||
|
saveToDisk: false,
|
||||||
|
data: demoData,
|
||||||
|
});
|
||||||
|
|
||||||
let pdfbuffer = Buffer.from(pdf);
|
let pdfbuffer = Buffer.from(pdf);
|
||||||
|
|
||||||
|
|
|
@ -146,8 +146,7 @@ export async function deleteUser(req: Request, res: Response): Promise<any> {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// sendmail
|
// sendmail
|
||||||
let mailhelper = new MailHelper();
|
await MailHelper.sendMail(
|
||||||
await mailhelper.sendMail(
|
|
||||||
user.mail,
|
user.mail,
|
||||||
`Email Bestätigung für Mitglieder Admin-Portal von ${CLUB_NAME}`,
|
`Email Bestätigung für Mitglieder Admin-Portal von ${CLUB_NAME}`,
|
||||||
`Ihr Nutzerkonto des Adminportals wurde erfolgreich gelöscht.`
|
`Ihr Nutzerkonto des Adminportals wurde erfolgreich gelöscht.`
|
||||||
|
|
|
@ -71,8 +71,7 @@ export async function inviteUser(req: Request, res: Response, isInvite: boolean
|
||||||
let token = await InviteCommandHandler.create(createInvite);
|
let token = await InviteCommandHandler.create(createInvite);
|
||||||
|
|
||||||
// sendmail
|
// sendmail
|
||||||
let mailhelper = new MailHelper();
|
await MailHelper.sendMail(
|
||||||
await mailhelper.sendMail(
|
|
||||||
mail,
|
mail,
|
||||||
`Email Bestätigung für Mitglieder Admin-Portal von ${CLUB_NAME}`,
|
`Email Bestätigung für Mitglieder Admin-Portal von ${CLUB_NAME}`,
|
||||||
`Öffne folgenden Link: ${origin}/${isInvite ? "invite" : "setup"}/verify?mail=${mail}&token=${token}`
|
`Öffne folgenden Link: ${origin}/${isInvite ? "invite" : "setup"}/verify?mail=${mail}&token=${token}`
|
||||||
|
|
|
@ -41,8 +41,7 @@ export async function startReset(req: Request, res: Response): Promise<any> {
|
||||||
let token = await ResetCommandHandler.create(createReset);
|
let token = await ResetCommandHandler.create(createReset);
|
||||||
|
|
||||||
// sendmail
|
// sendmail
|
||||||
let mailhelper = new MailHelper();
|
await MailHelper.sendMail(
|
||||||
await mailhelper.sendMail(
|
|
||||||
mail,
|
mail,
|
||||||
`Email Bestätigung für Mitglieder Admin-Portal von ${CLUB_NAME}`,
|
`Email Bestätigung für Mitglieder Admin-Portal von ${CLUB_NAME}`,
|
||||||
`Öffne folgenden Link: ${origin}/reset/reset?mail=${mail}&token=${token}`
|
`Öffne folgenden Link: ${origin}/reset/reset?mail=${mail}&token=${token}`
|
||||||
|
|
72
src/demodata/newsletter.data.ts
Normal file
72
src/demodata/newsletter.data.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import { calendar } from "../entity/calendar";
|
||||||
|
import { member } from "../entity/member";
|
||||||
|
import { Salutation } from "../enums/salutation";
|
||||||
|
|
||||||
|
export const newsletterDemoData: {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
newsletterTitle: string;
|
||||||
|
newsletterText: string;
|
||||||
|
newsletterSignatur: string;
|
||||||
|
dates: Array<
|
||||||
|
Partial<
|
||||||
|
calendar & {
|
||||||
|
formattedStarttime: string;
|
||||||
|
formattedFullStarttime: string;
|
||||||
|
formattedEndtime: string;
|
||||||
|
formattedFullEndtime: string;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
>;
|
||||||
|
recipient: Partial<member & { street: string; streetNumber: string; streetNumberAdd: string }>;
|
||||||
|
} = {
|
||||||
|
title: "Beispiel Newsletter Daten",
|
||||||
|
description: "Zusammenfassung der Demodaten.",
|
||||||
|
newsletterTitle: "<h1>Sehr geehrtes Feuerwehrmitglied</h1>",
|
||||||
|
newsletterText: "<p>zu folgenden Terminen möchten wir recht herzlich zur Teilnahme einladen:</p>",
|
||||||
|
newsletterSignatur: "<p>Mit freundlichen Grüßen</p><p>...</p>",
|
||||||
|
dates: [
|
||||||
|
{
|
||||||
|
title: "Termin 1",
|
||||||
|
content: "<p>Beschreibung eines Termins</p>",
|
||||||
|
starttime: new Date(),
|
||||||
|
formattedStarttime: new Date().toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
}),
|
||||||
|
formattedFullStarttime: new Date().toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
}),
|
||||||
|
endtime: new Date(),
|
||||||
|
formattedEndtime: new Date().toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
}),
|
||||||
|
formattedFullEndtime: new Date().toLocaleDateString("de-DE", {
|
||||||
|
weekday: "long",
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
}),
|
||||||
|
location: "Feuerwehrhaus",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
recipient: {
|
||||||
|
firstname: "Julian",
|
||||||
|
lastname: "Krauser",
|
||||||
|
salutation: Salutation.sir,
|
||||||
|
nameaffix: "",
|
||||||
|
street: "Straße",
|
||||||
|
streetNumber: "Hausnummer",
|
||||||
|
streetNumberAdd: "Adresszusatz",
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { newsletterDemoData } from "../demodata/newsletter.data";
|
||||||
import { protocolDemoData } from "../demodata/protocol.data";
|
import { protocolDemoData } from "../demodata/protocol.data";
|
||||||
import { PermissionModule } from "../type/permissionTypes";
|
import { PermissionModule } from "../type/permissionTypes";
|
||||||
|
|
||||||
|
@ -6,6 +7,8 @@ export abstract class DemoDataHelper {
|
||||||
switch (scope) {
|
switch (scope) {
|
||||||
case "protocol":
|
case "protocol":
|
||||||
return protocolDemoData;
|
return protocolDemoData;
|
||||||
|
case "newsletter":
|
||||||
|
return newsletterDemoData;
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,9 @@ export abstract class FileSystemHelper {
|
||||||
|
|
||||||
static getFilesInDirectory(directoryPath: string, filetype?: string): string[] {
|
static getFilesInDirectory(directoryPath: string, filetype?: string): string[] {
|
||||||
const fullPath = join(process.cwd(), directoryPath);
|
const fullPath = join(process.cwd(), directoryPath);
|
||||||
|
if (!existsSync(fullPath)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
return readdirSync(fullPath, { withFileTypes: true })
|
return readdirSync(fullPath, { withFileTypes: true })
|
||||||
.filter((dirent) => !dirent.isDirectory() && (!filetype || dirent.name.endsWith(filetype)))
|
.filter((dirent) => !dirent.isDirectory() && (!filetype || dirent.name.endsWith(filetype)))
|
||||||
.map((dirent) => dirent.name);
|
.map((dirent) => dirent.name);
|
||||||
|
|
|
@ -1,20 +1,16 @@
|
||||||
import { Transporter, createTransport, TransportOptions } from "nodemailer";
|
import { Transporter, createTransport, TransportOptions } from "nodemailer";
|
||||||
import { CLUB_NAME, MAIL_HOST, MAIL_PASSWORD, MAIL_PORT, MAIL_SECURE, MAIL_USERNAME } from "../env.defaults";
|
import { CLUB_NAME, MAIL_HOST, MAIL_PASSWORD, MAIL_PORT, MAIL_SECURE, MAIL_USERNAME } from "../env.defaults";
|
||||||
|
|
||||||
export default class MailHelper {
|
export default abstract class MailHelper {
|
||||||
private readonly transporter: Transporter;
|
private static readonly transporter: Transporter = createTransport({
|
||||||
|
host: MAIL_HOST,
|
||||||
constructor() {
|
port: MAIL_PORT,
|
||||||
this.transporter = createTransport({
|
secure: (MAIL_SECURE as "true" | "false") == "true",
|
||||||
host: MAIL_HOST,
|
auth: {
|
||||||
port: MAIL_PORT,
|
user: MAIL_USERNAME,
|
||||||
secure: (MAIL_SECURE as "true" | "false") == "true",
|
pass: MAIL_PASSWORD,
|
||||||
auth: {
|
},
|
||||||
user: MAIL_USERNAME,
|
} as TransportOptions);
|
||||||
pass: MAIL_PASSWORD,
|
|
||||||
},
|
|
||||||
} as TransportOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description send mail
|
* @description send mail
|
||||||
|
@ -23,7 +19,7 @@ export default class MailHelper {
|
||||||
* @param {string} content
|
* @param {string} content
|
||||||
* @returns {Prmose<*>}
|
* @returns {Prmose<*>}
|
||||||
*/
|
*/
|
||||||
async sendMail(target: string, subject: string, content: string): Promise<any> {
|
static async sendMail(target: string, subject: string, content: string): Promise<any> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.transporter
|
this.transporter
|
||||||
.sendMail({
|
.sendMail({
|
||||||
|
@ -31,6 +27,7 @@ export default class MailHelper {
|
||||||
to: target,
|
to: target,
|
||||||
subject,
|
subject,
|
||||||
text: content,
|
text: content,
|
||||||
|
html: content,
|
||||||
})
|
})
|
||||||
.then((info) => resolve(info.messageId))
|
.then((info) => resolve(info.messageId))
|
||||||
.catch((e) => reject(e));
|
.catch((e) => reject(e));
|
||||||
|
|
|
@ -26,7 +26,9 @@ export abstract class PdfExport {
|
||||||
|
|
||||||
const { header, footer, body } = await TemplateHelper.renderFileForModule({
|
const { header, footer, body } = await TemplateHelper.renderFileForModule({
|
||||||
module: template,
|
module: template,
|
||||||
|
headerData: data,
|
||||||
bodyData: data,
|
bodyData: data,
|
||||||
|
footerData: data,
|
||||||
title: title,
|
title: title,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -48,15 +48,15 @@ export abstract class TemplateHelper {
|
||||||
|
|
||||||
if (moduleTemplates.headerId) {
|
if (moduleTemplates.headerId) {
|
||||||
header = await this.getTemplateFromStore(moduleTemplates.headerId);
|
header = await this.getTemplateFromStore(moduleTemplates.headerId);
|
||||||
header = this.applyDataToTemplate(header, headerData);
|
header = this.applyDataToTemplate(header, { title, ...headerData });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moduleTemplates.footerId) {
|
if (moduleTemplates.footerId) {
|
||||||
footer = await this.getTemplateFromStore(moduleTemplates.footerId);
|
footer = await this.getTemplateFromStore(moduleTemplates.footerId);
|
||||||
footer = this.applyDataToTemplate(footer, footerData);
|
|
||||||
} else {
|
} else {
|
||||||
footer = this.getTemplateFromFile(module + ".footer");
|
footer = this.getTemplateFromFile(module + ".footer");
|
||||||
}
|
}
|
||||||
|
footer = this.applyDataToTemplate(footer, footerData);
|
||||||
|
|
||||||
if (moduleTemplates.bodyId) {
|
if (moduleTemplates.bodyId) {
|
||||||
body = await this.getTemplateFromStore(moduleTemplates.bodyId);
|
body = await this.getTemplateFromStore(moduleTemplates.bodyId);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { MigrationInterface, QueryRunner, Table, TableForeignKey } from "typeorm";
|
import { MigrationInterface, QueryRunner, Table, TableForeignKey } from "typeorm";
|
||||||
import { DB_TYPE } from "../env.defaults";
|
import { DB_TYPE } from "../env.defaults";
|
||||||
|
import { templateUsage } from "../entity/templateUsage";
|
||||||
|
|
||||||
export class Newsletter1735118780511 implements MigrationInterface {
|
export class Newsletter1735118780511 implements MigrationInterface {
|
||||||
name = "Newsletter1735118780511";
|
name = "Newsletter1735118780511";
|
||||||
|
@ -102,9 +103,24 @@ export class Newsletter1735118780511 implements MigrationInterface {
|
||||||
onUpdate: "RESTRICT",
|
onUpdate: "RESTRICT",
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await queryRunner.manager
|
||||||
|
.createQueryBuilder()
|
||||||
|
.insert()
|
||||||
|
.into(templateUsage)
|
||||||
|
.values({ scope: "newsletter" })
|
||||||
|
.orIgnore()
|
||||||
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.manager
|
||||||
|
.createQueryBuilder()
|
||||||
|
.delete()
|
||||||
|
.from(templateUsage)
|
||||||
|
.where({ scope: "newsletter" })
|
||||||
|
.execute();
|
||||||
|
|
||||||
const tableN = await queryRunner.getTable("newsletter");
|
const tableN = await queryRunner.getTable("newsletter");
|
||||||
const tableNR = await queryRunner.getTable("newsletter_recipients");
|
const tableNR = await queryRunner.getTable("newsletter_recipients");
|
||||||
const tableND = await queryRunner.getTable("newsletter_dates");
|
const tableND = await queryRunner.getTable("newsletter_dates");
|
||||||
|
|
|
@ -11,6 +11,9 @@ import {
|
||||||
synchronizeNewsletterDatesById,
|
synchronizeNewsletterDatesById,
|
||||||
synchronizeNewsletterById,
|
synchronizeNewsletterById,
|
||||||
synchronizeNewsletterRecipientsById,
|
synchronizeNewsletterRecipientsById,
|
||||||
|
sendNewsletterById,
|
||||||
|
createNewsletterMailPreviewById,
|
||||||
|
createNewsletterPrintoutPreviewById,
|
||||||
} from "../../controller/admin/newsletterController";
|
} from "../../controller/admin/newsletterController";
|
||||||
import PermissionHelper from "../../helpers/permissionHelper";
|
import PermissionHelper from "../../helpers/permissionHelper";
|
||||||
|
|
||||||
|
@ -40,6 +43,10 @@ router.get("/:newsletterId/printout/:filename", async (req: Request, res: Respon
|
||||||
await getNewsletterPrintoutByIdAndPrint(req, res);
|
await getNewsletterPrintoutByIdAndPrint(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get("/:newsletterId/printoutpreview", async (req: Request, res: Response) => {
|
||||||
|
await createNewsletterPrintoutPreviewById(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
"/",
|
"/",
|
||||||
PermissionHelper.passCheckMiddleware("create", "club", "protocol"),
|
PermissionHelper.passCheckMiddleware("create", "club", "protocol"),
|
||||||
|
@ -56,6 +63,18 @@ router.post(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.post("/:newsletterId/mailpreview", async (req: Request, res: Response) => {
|
||||||
|
await createNewsletterMailPreviewById(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
"/:newsletterId/send",
|
||||||
|
PermissionHelper.passCheckMiddleware("create", "club", "protocol"),
|
||||||
|
async (req: Request, res: Response) => {
|
||||||
|
await sendNewsletterById(req, res);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
router.patch(
|
router.patch(
|
||||||
"/:id/synchronize",
|
"/:id/synchronize",
|
||||||
PermissionHelper.passCheckMiddleware("update", "club", "protocol"),
|
PermissionHelper.passCheckMiddleware("update", "club", "protocol"),
|
||||||
|
@ -80,6 +99,4 @@ router.patch(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: send mails | send mail preview | render preview before print job
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
41
src/templates/newsletter.body.template.html
Normal file
41
src/templates/newsletter.body.template.html
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Newsletter</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>{{{newsletterTitle}}}</h1>
|
||||||
|
<p>{{{newsletterText}}}</p>
|
||||||
|
<br />
|
||||||
|
{{#each dates}}
|
||||||
|
<div>
|
||||||
|
<h2><b>{{this.formattedStarttime}}: {{this.title}}</b></h2>
|
||||||
|
<span>{{{this.content}}}</span>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<p>{{{newsletterSignatur}}}</p>
|
||||||
|
</body>
|
||||||
|
<style>
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
p,
|
||||||
|
span,
|
||||||
|
ul,
|
||||||
|
li {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2 {
|
||||||
|
color: #990b00;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</html>
|
4
src/templates/newsletter.footer.template.html
Normal file
4
src/templates/newsletter.footer.template.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<div style="font-size: 10pt; width: 100%; margin: 0 20px; padding-top: 5px; color: #888; border-top: 0.5px solid black">
|
||||||
|
{{recipient.lastname}}, {{recipient.firstname}}, {{recipient.street}} {{recipient.streetNumber}}
|
||||||
|
{{recipient.streetNumberAdd}}
|
||||||
|
</div>
|
Loading…
Reference in a new issue