diff --git a/src/command/newsletterConfigCommand.ts b/src/command/newsletterConfigCommand.ts new file mode 100644 index 0000000..861e3e3 --- /dev/null +++ b/src/command/newsletterConfigCommand.ts @@ -0,0 +1,6 @@ +import { NewsletterConfigType } from "../enums/newsletterConfigType"; + +export interface SetNewsletterConfigCommand { + comTypeId: number; + config: NewsletterConfigType; +} diff --git a/src/command/newsletterConfigCommandHandler.ts b/src/command/newsletterConfigCommandHandler.ts new file mode 100644 index 0000000..d054c38 --- /dev/null +++ b/src/command/newsletterConfigCommandHandler.ts @@ -0,0 +1,30 @@ +import { dataSource } from "../data-source"; +import { newsletterConfig } from "../entity/newsletterConfig"; +import InternalException from "../exceptions/internalException"; +import { SetNewsletterConfigCommand } from "./newsletterConfigCommand"; + +export default abstract class NewsletterConfigCommandHandler { + /** + * @description set newsletterConfig + * @param SetNewsletterConfigCommand + * @returns {Promise} + */ + static async setConfig(setNewsletterConfig: SetNewsletterConfigCommand): Promise { + return await dataSource + .createQueryBuilder() + .insert() + .into(newsletterConfig) + .values({ + comTypeId: setNewsletterConfig.comTypeId, + config: setNewsletterConfig.config, + }) + .orUpdate(["config"], "comTypeId") + .execute() + .then((result) => { + return result.identifiers[0].id; + }) + .catch((err) => { + throw new InternalException("Failed setting newsletterConfig", err); + }); + } +} diff --git a/src/controller/admin/newsletterConfigController.ts b/src/controller/admin/newsletterConfigController.ts new file mode 100644 index 0000000..790d093 --- /dev/null +++ b/src/controller/admin/newsletterConfigController.ts @@ -0,0 +1,49 @@ +import { Request, Response } from "express"; +import NewsletterConfigService from "../../service/newsletterConfigService"; +import NewsletterConfigFactory from "../../factory/admin/newsletterConfig"; +import NewsletterConfigCommandHandler from "../../command/newsletterConfigCommandHandler"; +import { SetNewsletterConfigCommand } from "../../command/newsletterConfigCommand"; + +/** + * @description get all newsletterConfigs + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getAllNewsletterConfigs(req: Request, res: Response): Promise { + let newsletterConfigs = await NewsletterConfigService.getAll(); + + res.json(NewsletterConfigFactory.mapToBase(newsletterConfigs)); +} + +/** + * @description get newsletterConfig by id + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getNewsletterConfigById(req: Request, res: Response): Promise { + let comId = parseInt(req.params.comId); + let newsletterConfig = await NewsletterConfigService.getByComId(comId); + + res.json(NewsletterConfigFactory.mapToSingle(newsletterConfig)); +} + +/** + * @description set newsletterConfig + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function setNewsletterConfig(req: Request, res: Response): Promise { + let comTypeId = req.body.comTypeId; + let config = req.body.config; + + let createNewsletterConfig: SetNewsletterConfigCommand = { + comTypeId, + config, + }; + let id = await NewsletterConfigCommandHandler.setConfig(createNewsletterConfig); + + res.send(id); +} diff --git a/src/controller/admin/newsletterController.ts b/src/controller/admin/newsletterController.ts index 1d4efb0..11bf8c2 100644 --- a/src/controller/admin/newsletterController.ts +++ b/src/controller/admin/newsletterController.ts @@ -146,6 +146,7 @@ export async function createNewsletterPrintoutById(req: Request, res: Response): // check if all users have mail or adress // squash all files to single for printing // use Helper for Newsletter printing and mail sending + // default template res.sendStatus(204); } diff --git a/src/data-source.ts b/src/data-source.ts index 7b97e03..7e8321f 100644 --- a/src/data-source.ts +++ b/src/data-source.ts @@ -59,6 +59,8 @@ import { newsletter } from "./entity/newsletter"; import { newsletterDates } from "./entity/newsletterDates"; import { newsletterRecipients } from "./entity/newsletterRecipients"; import { Newsletter1735118780511 } from "./migrations/1735118780511-newsletter"; +import { newsletterConfig } from "./entity/newsletterConfig"; +import { NewsletterConfig1735207446910 } from "./migrations/1735207446910-newsletterConfig"; const dataSource = new DataSource({ type: DB_TYPE as any, @@ -103,6 +105,7 @@ const dataSource = new DataSource({ newsletter, newsletterDates, newsletterRecipients, + newsletterConfig, memberView, memberExecutivePositionsView, memberQualificationsView, @@ -128,6 +131,7 @@ const dataSource = new DataSource({ Template1734854680201, TemplateUsage1734949173739, Newsletter1735118780511, + NewsletterConfig1735207446910, ], migrationsRun: true, migrationsTransactionMode: "each", diff --git a/src/entity/newsletterConfig.ts b/src/entity/newsletterConfig.ts new file mode 100644 index 0000000..6ad74ab --- /dev/null +++ b/src/entity/newsletterConfig.ts @@ -0,0 +1,30 @@ +import { Column, Entity, ManyToOne, PrimaryColumn } from "typeorm"; +import { NewsletterConfigType } from "../enums/newsletterConfigType"; +import { communicationType } from "./communicationType"; + +@Entity() +export class newsletterConfig { + @PrimaryColumn({ type: "int" }) + comTypeId: number; + + @Column({ + type: "varchar", + length: "255", + transformer: { + to(value: NewsletterConfigType) { + return value.toString(); + }, + from(value: string) { + return NewsletterConfigType[value as keyof typeof NewsletterConfigType]; + }, + }, + }) + config: NewsletterConfigType; + + @ManyToOne(() => communicationType, { + nullable: false, + onDelete: "CASCADE", + onUpdate: "RESTRICT", + }) + comType: communicationType; +} diff --git a/src/enums/newsletterConfigType.ts b/src/enums/newsletterConfigType.ts new file mode 100644 index 0000000..4703494 --- /dev/null +++ b/src/enums/newsletterConfigType.ts @@ -0,0 +1,4 @@ +export enum NewsletterConfigType { + pdf = "pdf", + mail = "mail", +} diff --git a/src/factory/admin/newsletterConfig.ts b/src/factory/admin/newsletterConfig.ts new file mode 100644 index 0000000..854bd83 --- /dev/null +++ b/src/factory/admin/newsletterConfig.ts @@ -0,0 +1,27 @@ +import { newsletterConfig } from "../../entity/newsletterConfig"; +import { NewsletterConfigViewModel } from "../../viewmodel/admin/newsletterConfig.models"; +import CommunicationTypeFactory from "./communicationType"; + +export default abstract class NewsletterConfigFactory { + /** + * @description map record to newsletterConfig + * @param {newsletterConfig} record + * @returns {NewsletterConfigViewModel} + */ + public static mapToSingle(record: newsletterConfig): NewsletterConfigViewModel { + return { + comTypeId: record.comTypeId, + config: record.config, + comType: record?.comType ? CommunicationTypeFactory.mapToSingle(record.comType) : null, + }; + } + + /** + * @description map records to newsletterConfig + * @param {Array} records + * @returns {Array} + */ + public static mapToBase(records: Array): Array { + return records.map((r) => this.mapToSingle(r)); + } +} diff --git a/src/migrations/1735207446910-newsletterConfig.ts b/src/migrations/1735207446910-newsletterConfig.ts new file mode 100644 index 0000000..8f893d9 --- /dev/null +++ b/src/migrations/1735207446910-newsletterConfig.ts @@ -0,0 +1,39 @@ +import { MigrationInterface, QueryRunner, Table, TableForeignKey } from "typeorm"; +import { DB_TYPE } from "../env.defaults"; + +export class NewsletterConfig1735207446910 implements MigrationInterface { + name = "NewsletterConfig1735207446910"; + + public async up(queryRunner: QueryRunner): Promise { + const variableType_int = DB_TYPE == "mysql" ? "int" : "integer"; + + await queryRunner.createTable( + new Table({ + name: "newsletter_config", + columns: [ + { name: "comTypeId", type: variableType_int, isPrimary: true, isNullable: false }, + { name: "config", type: "varchar", length: "255", isNullable: false }, + ], + }), + true + ); + + await queryRunner.createForeignKey( + "newsletter_config", + new TableForeignKey({ + columnNames: ["comTypeId"], + referencedColumnNames: ["id"], + referencedTableName: "communication_type", + onDelete: "CASCADE", + onUpdate: "RESTRICT", + }) + ); + } + + public async down(queryRunner: QueryRunner): Promise { + const table = await queryRunner.getTable("newsletter_config"); + const foreignKey = table.foreignKeys.find((fk) => fk.columnNames.indexOf("comTypeId") !== -1); + await queryRunner.dropForeignKey("newsletter_config", foreignKey); + await queryRunner.dropTable("newsletter_config"); + } +} diff --git a/src/routes/admin/index.ts b/src/routes/admin/index.ts index 4da8c12..8d627af 100644 --- a/src/routes/admin/index.ts +++ b/src/routes/admin/index.ts @@ -10,6 +10,7 @@ import calendarType from "./calendarType"; import queryStore from "./queryStore"; import template from "./template"; import templateUsage from "./templateUsage"; +import newsletterConfig from "./newsletterConfig"; import member from "./member"; import protocol from "./protocol"; @@ -44,6 +45,11 @@ router.use("/calendartype", PermissionHelper.passCheckMiddleware("read", "settin router.use("/querystore", PermissionHelper.passCheckMiddleware("read", "settings", "query_store"), queryStore); router.use("/template", PermissionHelper.passCheckMiddleware("read", "settings", "template"), template); router.use("/templateusage", PermissionHelper.passCheckMiddleware("read", "settings", "template_usage"), templateUsage); +router.use( + "/newsletterconfig", + PermissionHelper.passCheckMiddleware("read", "settings", "newsletter_config"), + newsletterConfig +); router.use("/member", PermissionHelper.passCheckMiddleware("read", "club", "member"), member); router.use("/protocol", PermissionHelper.passCheckMiddleware("read", "club", "protocol"), protocol); diff --git a/src/routes/admin/newsletterConfig.ts b/src/routes/admin/newsletterConfig.ts new file mode 100644 index 0000000..c1be19d --- /dev/null +++ b/src/routes/admin/newsletterConfig.ts @@ -0,0 +1,27 @@ +import express, { Request, Response } from "express"; +import { + getAllNewsletterConfigs, + getNewsletterConfigById, + setNewsletterConfig, +} from "../../controller/admin/newsletterConfigController"; +import PermissionHelper from "../../helpers/permissionHelper"; + +var router = express.Router({ mergeParams: true }); + +router.get("/", async (req: Request, res: Response) => { + await getAllNewsletterConfigs(req, res); +}); + +router.get("/:id", async (req: Request, res: Response) => { + await getNewsletterConfigById(req, res); +}); + +router.put( + "/", + PermissionHelper.passCheckMiddleware("create", "settings", "newsletter_config"), + async (req: Request, res: Response) => { + await setNewsletterConfig(req, res); + } +); + +export default router; diff --git a/src/service/newsletterConfigService.ts b/src/service/newsletterConfigService.ts new file mode 100644 index 0000000..f85970d --- /dev/null +++ b/src/service/newsletterConfigService.ts @@ -0,0 +1,43 @@ +import { dataSource } from "../data-source"; +import { newsletterConfig } from "../entity/newsletterConfig"; +import { member } from "../entity/member"; +import InternalException from "../exceptions/internalException"; + +export default abstract class NewsletterConfigService { + /** + * @description get all newsletterConfigs + * @returns {Promise>} + */ + static async getAll(): Promise> { + return await dataSource + .getRepository(newsletterConfig) + .createQueryBuilder("newsletterConfig") + .leftJoinAndSelect("newsletterConfig.comType", "comType") + .getMany() + .then((res) => { + return res; + }) + .catch((err) => { + throw new InternalException("newsletterConfigs not found", err); + }); + } + + /** + * @description get newsletterConfig by id + * @returns {Promise} + */ + static async getByComId(comId: number): Promise { + return await dataSource + .getRepository(newsletterConfig) + .createQueryBuilder("newsletterConfig") + .leftJoinAndSelect("newsletterConfig.comType", "comType") + .where("newsletterConfig.comTypId = :comTypId", { icomTypId: comId }) + .getOneOrFail() + .then((res) => { + return res; + }) + .catch((err) => { + throw new InternalException("newsletterConfig not found by cmId", err); + }); + } +} diff --git a/src/service/newsletterService.ts b/src/service/newsletterService.ts index cd05747..f522233 100644 --- a/src/service/newsletterService.ts +++ b/src/service/newsletterService.ts @@ -1,6 +1,5 @@ import { dataSource } from "../data-source"; import { newsletter } from "../entity/newsletter"; -import { member } from "../entity/member"; import InternalException from "../exceptions/internalException"; export default abstract class NewsletterService { diff --git a/src/viewmodel/admin/newsletterConfig.models.ts b/src/viewmodel/admin/newsletterConfig.models.ts new file mode 100644 index 0000000..d21e4bf --- /dev/null +++ b/src/viewmodel/admin/newsletterConfig.models.ts @@ -0,0 +1,8 @@ +import { NewsletterConfigType } from "../../enums/newsletterConfigType"; +import { CommunicationTypeViewModel } from "./communicationType.models"; + +export interface NewsletterConfigViewModel { + comTypeId: number; + config: NewsletterConfigType; + comType: CommunicationTypeViewModel; +}