From 597feef9ef53837974c0c5efdb4df32cf507bd77 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Tue, 3 Dec 2024 19:11:09 +0100 Subject: [PATCH 1/3] return json or ics and provide all day entries --- src/controller/publicController.ts | 102 ++++++++++++++++++----------- 1 file changed, 63 insertions(+), 39 deletions(-) diff --git a/src/controller/publicController.ts b/src/controller/publicController.ts index ef675fa..1ba5134 100644 --- a/src/controller/publicController.ts +++ b/src/controller/publicController.ts @@ -4,6 +4,8 @@ import CalendarTypeService from "../service/calendarTypeService"; import { calendar } from "../entity/calendar"; import { createEvents } from "ics"; import moment from "moment"; +import InternalException from "../exceptions/internalException"; +import CalendarFactory from "../factory/admin/calendar"; /** * @description get all calendar items by types or nscdr @@ -13,6 +15,11 @@ import moment from "moment"; */ export async function getCalendarItemsByTypes(req: Request, res: Response): Promise { let types = Array.isArray(req.query.types) ? req.query.types : [req.query.types]; + let output = (req.query.output as "ics" | "json") ?? "ics"; + + if (output != "ics" && output != "json") { + throw new InternalException("set output query value to `ics` or `json` (defaults to `ics`)"); + } let items: Array = []; if (types.length == 0) { @@ -22,45 +29,62 @@ export async function getCalendarItemsByTypes(req: Request, res: Response): Prom items = await CalendarService.getByTypeNSCDR(); } - let events = createEvents( - items.map((i) => ({ - calName: process.env.CLUB_NAME, - uid: i.id, - sequence: 1, - start: moment(i.starttime) - .format("YYYY-M-D-H-m") - .split("-") - .map((a) => parseInt(a)) as [number, number, number, number, number], - end: moment(i.endtime) - .format("YYYY-M-D-H-m") - .split("-") - .map((a) => parseInt(a)) as [number, number, number, number, number], - title: i.title, - description: i.content, - location: i.location, - categories: [i.type.type], - created: moment(i.createdAt) - .format("YYYY-M-D-H-m") - .split("-") - .map((a) => parseInt(a)) as [number, number, number, number, number], - lastModified: moment(i.updatedAt) - .format("YYYY-M-D-H-m") - .split("-") - .map((a) => parseInt(a)) as [number, number, number, number, number], - transp: "OPAQUE" as "OPAQUE", - url: "https://www.ff-merching.de", - alarms: [ - { - action: "display", - description: "Erinnerung", - trigger: { - minutes: 30, - before: true, + if (output == "json") { + res.json(CalendarFactory.mapToBase(items)); + } else { + let events = createEvents( + items.map((i) => ({ + calName: process.env.CLUB_NAME, + uid: i.id, + sequence: 1, + ...(i.allDay + ? { + start: moment(i.starttime) + .format("YYYY-M-D") + .split("-") + .map((a) => parseInt(a)) as [number, number, number], + end: moment(i.endtime) + .format("YYYY-M-D") + .split("-") + .map((a) => parseInt(a)) as [number, number, number], + } + : { + start: moment(i.starttime) + .format("YYYY-M-D-H-m") + .split("-") + .map((a) => parseInt(a)) as [number, number, number, number, number], + end: moment(i.endtime) + .format("YYYY-M-D-H-m") + .split("-") + .map((a) => parseInt(a)) as [number, number, number, number, number], + }), + title: i.title, + description: i.content, + location: i.location, + categories: [i.type.type], + created: moment(i.createdAt) + .format("YYYY-M-D-H-m") + .split("-") + .map((a) => parseInt(a)) as [number, number, number, number, number], + lastModified: moment(i.updatedAt) + .format("YYYY-M-D-H-m") + .split("-") + .map((a) => parseInt(a)) as [number, number, number, number, number], + transp: "OPAQUE" as "OPAQUE", + url: "https://www.ff-merching.de", + alarms: [ + { + action: "display", + description: "Erinnerung", + trigger: { + minutes: 30, + before: true, + }, }, - }, - ], - })) - ); + ], + })) + ); - res.type("ics").send(events.value); + res.type("ics").send(events.value); + } } From 8f49533fcbe2a36d8899bccb9cf9d318e4a71b43 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Tue, 3 Dec 2024 19:29:38 +0100 Subject: [PATCH 2/3] secure type with passphrase --- src/command/calendarTypeCommand.ts | 2 ++ src/command/calendarTypeCommandHandler.ts | 2 ++ src/controller/admin/calendarController.ts | 4 ++++ src/controller/publicController.ts | 11 ++++++++-- src/data-source.ts | 2 ++ src/entity/calendarType.ts | 3 +++ src/factory/admin/calendarType.ts | 1 + .../1733249553766-securingCalendarType.ts | 20 +++++++++++++++++++ src/viewmodel/admin/calendarType.models.ts | 1 + 9 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/migrations/1733249553766-securingCalendarType.ts diff --git a/src/command/calendarTypeCommand.ts b/src/command/calendarTypeCommand.ts index fdab618..d796058 100644 --- a/src/command/calendarTypeCommand.ts +++ b/src/command/calendarTypeCommand.ts @@ -2,6 +2,7 @@ export interface CreateCalendarTypeCommand { type: string; nscdr: boolean; color: string; + passphrase?: string; } export interface UpdateCalendarTypeCommand { @@ -9,6 +10,7 @@ export interface UpdateCalendarTypeCommand { type: string; nscdr: boolean; color: string; + passphrase?: string; } export interface DeleteCalendarTypeCommand { diff --git a/src/command/calendarTypeCommandHandler.ts b/src/command/calendarTypeCommandHandler.ts index 0425425..223288c 100644 --- a/src/command/calendarTypeCommandHandler.ts +++ b/src/command/calendarTypeCommandHandler.ts @@ -18,6 +18,7 @@ export default abstract class CalendarTypeCommandHandler { type: createCalendarType.type, nscdr: createCalendarType.nscdr, color: createCalendarType.color, + passphrase: createCalendarType.nscdr ? null : createCalendarType.passphrase, }) .execute() .then((result) => { @@ -41,6 +42,7 @@ export default abstract class CalendarTypeCommandHandler { type: updateCalendarType.type, nscdr: updateCalendarType.nscdr, color: updateCalendarType.color, + passphrase: updateCalendarType.nscdr ? null : updateCalendarType.passphrase, }) .where("id = :id", { id: updateCalendarType.id }) .execute() diff --git a/src/controller/admin/calendarController.ts b/src/controller/admin/calendarController.ts index 0b319b1..f6a3bcd 100644 --- a/src/controller/admin/calendarController.ts +++ b/src/controller/admin/calendarController.ts @@ -101,11 +101,13 @@ export async function createCalendarType(req: Request, res: Response): Promise} @@ -22,8 +23,14 @@ export async function getCalendarItemsByTypes(req: Request, res: Response): Prom } let items: Array = []; - if (types.length == 0) { - let typeIds = await CalendarTypeService.getByTypes(types as Array); + if (types.length != 0) { + let typeIds = await CalendarTypeService.getByTypes((types as Array).map((t) => t.split(":")[0])); + typeIds = typeIds.filter( + (ti) => + ti.passphrase == null || + ti.passphrase == "" || + ti.passphrase == (types as Array).find((t) => t.includes(ti.type)).split(":")[1] + ); items = await CalendarService.getByTypes(typeIds.map((t) => t.id)); } else { items = await CalendarService.getByTypeNSCDR(); diff --git a/src/data-source.ts b/src/data-source.ts index c7fec9f..5271c7c 100644 --- a/src/data-source.ts +++ b/src/data-source.ts @@ -43,6 +43,7 @@ import { Calendar1729947763295 } from "./migrations/1729947763295-calendar"; import { reset } from "./entity/reset"; import { ResetToken1732358596823 } from "./migrations/1732358596823-resetToken"; import { SMSAlarming1732696919191 } from "./migrations/1732696919191-SMSAlarming"; +import { SecuringCalendarType1733249553766 } from "./migrations/1733249553766-securingCalendarType"; const dataSource = new DataSource({ type: DB_TYPE as any, @@ -96,6 +97,7 @@ const dataSource = new DataSource({ Calendar1729947763295, ResetToken1732358596823, SMSAlarming1732696919191, + SecuringCalendarType1733249553766, ], migrationsRun: true, migrationsTransactionMode: "each", diff --git a/src/entity/calendarType.ts b/src/entity/calendarType.ts index 5f696cc..0214117 100644 --- a/src/entity/calendarType.ts +++ b/src/entity/calendarType.ts @@ -15,6 +15,9 @@ export class calendarType { @Column({ type: "varchar", length: 255 }) color: string; + @Column({ type: "varchar", length: 255, nullable: true, default: null }) + passphrase: string | null; + @OneToMany(() => calendar, (c) => c.type, { nullable: false, onDelete: "RESTRICT", diff --git a/src/factory/admin/calendarType.ts b/src/factory/admin/calendarType.ts index d1f6850..25aed4e 100644 --- a/src/factory/admin/calendarType.ts +++ b/src/factory/admin/calendarType.ts @@ -13,6 +13,7 @@ export default abstract class CalendarTypeFactory { type: record.type, nscdr: record.nscdr, color: record.color, + passphrase: record.passphrase, }; } diff --git a/src/migrations/1733249553766-securingCalendarType.ts b/src/migrations/1733249553766-securingCalendarType.ts new file mode 100644 index 0000000..2b486de --- /dev/null +++ b/src/migrations/1733249553766-securingCalendarType.ts @@ -0,0 +1,20 @@ +import { MigrationInterface, QueryRunner, TableColumn } from "typeorm"; + +export class SecuringCalendarType1733249553766 implements MigrationInterface { + name = "SecuringCalendarType1733249553766"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.addColumns("calendar_type", [ + new TableColumn({ + name: "passphrase", + type: "varchar", + length: "255", + isNullable: true, + }), + ]); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropColumn("calendar_type", "passphrase"); + } +} diff --git a/src/viewmodel/admin/calendarType.models.ts b/src/viewmodel/admin/calendarType.models.ts index e57dcb1..54dc465 100644 --- a/src/viewmodel/admin/calendarType.models.ts +++ b/src/viewmodel/admin/calendarType.models.ts @@ -3,4 +3,5 @@ export interface CalendarTypeViewModel { type: string; nscdr: boolean; color: string; + passphrase: string | null; } From 7810f05513da1b51d33b723773b32708f11186c7 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Wed, 4 Dec 2024 18:58:31 +0100 Subject: [PATCH 3/3] query types --- src/controller/publicController.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/controller/publicController.ts b/src/controller/publicController.ts index 5b3769a..8c627fc 100644 --- a/src/controller/publicController.ts +++ b/src/controller/publicController.ts @@ -22,6 +22,8 @@ export async function getCalendarItemsByTypes(req: Request, res: Response): Prom throw new InternalException("set output query value to `ics` or `json` (defaults to `ics`)"); } + types = types.filter((t) => t); + let items: Array = []; if (types.length != 0) { let typeIds = await CalendarTypeService.getByTypes((types as Array).map((t) => t.split(":")[0]));