newsletter CRUD & pdf

This commit is contained in:
Julian Krauser 2024-12-25 12:22:28 +01:00
parent e9b29f8acf
commit 01ce3fdd39
31 changed files with 1185 additions and 23 deletions

View file

@ -0,0 +1,18 @@
export interface CreateNewsletterCommand {
title: string;
}
export interface SynchronizeNewsletterCommand {
id: number;
title: string;
description: string;
newsletterTitle: string;
newsletterText: string;
newsletterSignatur: string;
recipientsByQueryId?: number;
}
export interface SendNewsletterCommand {
id: number;
isSent: boolean;
}

View file

@ -0,0 +1,73 @@
import { dataSource } from "../data-source";
import { newsletter } from "../entity/newsletter";
import InternalException from "../exceptions/internalException";
import { CreateNewsletterCommand, SendNewsletterCommand, SynchronizeNewsletterCommand } from "./newsletterCommand";
export default abstract class NewsletterCommandHandler {
/**
* @description create newsletter
* @param CreateNewsletterCommand
* @returns {Promise<number>}
*/
static async create(createNewsletter: CreateNewsletterCommand): Promise<number> {
return await dataSource
.createQueryBuilder()
.insert()
.into(newsletter)
.values({
title: createNewsletter.title,
})
.execute()
.then((result) => {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating newsletter", err);
});
}
/**
* @description sync newsletter
* @param SynchronizeNewsletterCommand
* @returns {Promise<void>}
*/
static async sync(syncNewsletter: SynchronizeNewsletterCommand): Promise<void> {
return await dataSource
.createQueryBuilder()
.update(newsletter)
.set({
title: syncNewsletter.title,
description: syncNewsletter.description,
newsletterTitle: syncNewsletter.newsletterTitle,
newsletterText: syncNewsletter.newsletterText,
newsletterSignatur: syncNewsletter.newsletterSignatur,
recipientsByQueryId: syncNewsletter.recipientsByQueryId,
})
.where("id = :id", { id: syncNewsletter.id })
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed synching newsletter", err);
});
}
/**
* @description send newsletter
* @param SendNewsletterCommand
* @returns {Promise<void>}
*/
static async send(syncNewsletter: SendNewsletterCommand): Promise<void> {
return await dataSource
.createQueryBuilder()
.update(newsletter)
.set({
isSent: syncNewsletter.isSent,
})
.where("id = :id", { id: syncNewsletter.id })
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed setting newsletter send state", err);
});
}
}

View file

@ -0,0 +1,10 @@
export interface SynchronizeNewsletterDatesCommand {
newsletterId: number;
dates: Array<NewsletterDateCommand>;
}
export interface NewsletterDateCommand {
calendarId: number;
diffTitle?: string;
diffDescription?: string;
}

View file

@ -0,0 +1,95 @@
import { DeleteResult, EntityManager, InsertResult, UpdateResult } from "typeorm";
import { dataSource } from "../data-source";
import InternalException from "../exceptions/internalException";
import NewsletterDatesService from "../service/newsletterDatesService";
import { NewsletterDateCommand, SynchronizeNewsletterDatesCommand } from "./newsletterDatesCommand";
import { newsletterDates } from "../entity/newsletterDates";
export default abstract class NewsletterDatesCommandHandler {
/**
* @description sync newsletter dates
* @param {SynchronizeNewsletterDatesCommand} syncNewsletterDates
* @returns {Promise<void>}
*/
static async sync(syncNewsletterDates: SynchronizeNewsletterDatesCommand): Promise<void> {
let currentDates = await NewsletterDatesService.getAll(syncNewsletterDates.newsletterId);
return await dataSource.manager
.transaction(async (manager) => {
let newDates = syncNewsletterDates.dates.filter(
(r) => !currentDates.map((np) => np.calendarId).includes(r.calendarId)
);
let removeDates = currentDates.filter(
(r) => !syncNewsletterDates.dates.map((np) => np.calendarId).includes(r.calendarId)
);
let keptDates = currentDates.filter((r) =>
syncNewsletterDates.dates.map((np) => np.calendarId).includes(r.calendarId)
);
if (newDates.length != 0) {
await this.syncPresenceAdd(manager, syncNewsletterDates.newsletterId, newDates);
}
if (removeDates.length != 0) {
await this.syncPresenceRemove(manager, syncNewsletterDates.newsletterId, removeDates);
}
for (const date of keptDates) {
await this.syncPresenceUpdate(manager, syncNewsletterDates.newsletterId, date);
}
})
.then(() => {})
.catch((err) => {
throw new InternalException("Failed syncing newsletter dates", err);
});
}
private static async syncPresenceAdd(
manager: EntityManager,
newsletterId: number,
dates: Array<NewsletterDateCommand>
): Promise<InsertResult> {
return await manager
.createQueryBuilder()
.insert()
.into(newsletterDates)
.values(
dates.map((d) => ({
...d,
newsletterId: newsletterId,
}))
)
.execute();
}
private static async syncPresenceUpdate(
manager: EntityManager,
newsletterId: number,
date: NewsletterDateCommand
): Promise<UpdateResult> {
return await manager
.createQueryBuilder()
.update(newsletterDates)
.set({
diffTitle: date.diffTitle,
diffDescription: date.diffDescription,
})
.where("calendarId = :calendarId", { calendarId: date.calendarId })
.andWhere("newsletterId = :newsletterId", { newsletterId })
.execute();
}
private static async syncPresenceRemove(
manager: EntityManager,
newsletterId: number,
dates: Array<NewsletterDateCommand>
): Promise<DeleteResult> {
return await manager
.createQueryBuilder()
.delete()
.from(newsletterDates)
.where("calendarId IN (:...ids)", { ids: dates.map((d) => d.calendarId) })
.andWhere("newsletterId = :newsletterId", { newsletterId })
.execute();
}
}

View file

@ -0,0 +1,9 @@
export interface SynchronizeNewsletterRecipientsCommand {
newsletterId: number;
recipients: Array<NewsletterRecipientCommand>;
}
export interface NewsletterRecipientCommand {
memberId: number;
addedManually: boolean;
}

View file

@ -0,0 +1,94 @@
import { DeleteResult, EntityManager, InsertResult, UpdateResult } from "typeorm";
import { dataSource } from "../data-source";
import InternalException from "../exceptions/internalException";
import NewsletterRecipientsService from "../service/newsletterRecipientsService";
import { NewsletterRecipientCommand, SynchronizeNewsletterRecipientsCommand } from "./newsletterRecipientsCommand";
import { newsletterRecipients } from "../entity/newsletterRecipients";
export default abstract class NewsletterRecipientsCommandHandler {
/**
* @description sync newsletterRecipients
* @param {SynchronizeNewsletterRecipientsCommand} syncNewsletterRecipients
* @returns {Promise<void>}
*/
static async sync(syncNewsletterRecipients: SynchronizeNewsletterRecipientsCommand): Promise<void> {
let currentRecipients = await NewsletterRecipientsService.getAll(syncNewsletterRecipients.newsletterId);
return await dataSource.manager
.transaction(async (manager) => {
let newRecipients = syncNewsletterRecipients.recipients.filter(
(r) => !currentRecipients.map((np) => np.memberId).includes(r.memberId)
);
let removeRecipients = currentRecipients.filter(
(r) => !syncNewsletterRecipients.recipients.map((np) => np.memberId).includes(r.memberId)
);
let keptRecipients = currentRecipients.filter((r) =>
syncNewsletterRecipients.recipients.map((np) => np.memberId).includes(r.memberId)
);
if (newRecipients.length != 0) {
await this.syncPresenceAdd(manager, syncNewsletterRecipients.newsletterId, newRecipients);
}
if (removeRecipients.length != 0) {
await this.syncPresenceRemove(manager, syncNewsletterRecipients.newsletterId, removeRecipients);
}
for (const recipient of keptRecipients) {
await this.syncPresenceUpdate(manager, syncNewsletterRecipients.newsletterId, recipient);
}
})
.then(() => {})
.catch((err) => {
throw new InternalException("Failed syncing newsletter recipients", err);
});
}
private static async syncPresenceAdd(
manager: EntityManager,
newsletterId: number,
recipients: Array<NewsletterRecipientCommand>
): Promise<InsertResult> {
return await manager
.createQueryBuilder()
.insert()
.into(newsletterRecipients)
.values(
recipients.map((d) => ({
...d,
newsletterId: newsletterId,
}))
)
.execute();
}
private static async syncPresenceUpdate(
manager: EntityManager,
newsletterId: number,
recipient: NewsletterRecipientCommand
): Promise<UpdateResult> {
return await manager
.createQueryBuilder()
.update(newsletterRecipients)
.set({
addedManually: recipient.addedManually,
})
.where("memberId = :memberId", { memberId: recipient.memberId })
.andWhere("newsletterId = :newsletterId", { newsletterId })
.execute();
}
private static async syncPresenceRemove(
manager: EntityManager,
newsletterId: number,
recipients: Array<NewsletterRecipientCommand>
): Promise<DeleteResult> {
return await manager
.createQueryBuilder()
.delete()
.from(newsletterRecipients)
.where("memberId IN (:...ids)", { ids: recipients.map((d) => d.memberId) })
.andWhere("newsletterId = :newsletterId", { newsletterId })
.execute();
}
}