Merge pull request '#20-calendar-api' (#21) from #20-calendar-api into main

Reviewed-on: Ehrenamt/member-administration-server#21
This commit is contained in:
Julian Krauser 2024-12-12 14:04:56 +00:00
commit 4007000c60
9 changed files with 109 additions and 41 deletions

View file

@ -2,6 +2,7 @@ export interface CreateCalendarTypeCommand {
type: string; type: string;
nscdr: boolean; nscdr: boolean;
color: string; color: string;
passphrase?: string;
} }
export interface UpdateCalendarTypeCommand { export interface UpdateCalendarTypeCommand {
@ -9,6 +10,7 @@ export interface UpdateCalendarTypeCommand {
type: string; type: string;
nscdr: boolean; nscdr: boolean;
color: string; color: string;
passphrase?: string;
} }
export interface DeleteCalendarTypeCommand { export interface DeleteCalendarTypeCommand {

View file

@ -18,6 +18,7 @@ export default abstract class CalendarTypeCommandHandler {
type: createCalendarType.type, type: createCalendarType.type,
nscdr: createCalendarType.nscdr, nscdr: createCalendarType.nscdr,
color: createCalendarType.color, color: createCalendarType.color,
passphrase: createCalendarType.nscdr ? null : createCalendarType.passphrase,
}) })
.execute() .execute()
.then((result) => { .then((result) => {
@ -41,6 +42,7 @@ export default abstract class CalendarTypeCommandHandler {
type: updateCalendarType.type, type: updateCalendarType.type,
nscdr: updateCalendarType.nscdr, nscdr: updateCalendarType.nscdr,
color: updateCalendarType.color, color: updateCalendarType.color,
passphrase: updateCalendarType.nscdr ? null : updateCalendarType.passphrase,
}) })
.where("id = :id", { id: updateCalendarType.id }) .where("id = :id", { id: updateCalendarType.id })
.execute() .execute()

View file

@ -101,11 +101,13 @@ export async function createCalendarType(req: Request, res: Response): Promise<a
const type = req.body.type; const type = req.body.type;
const nscdr = req.body.nscdr; const nscdr = req.body.nscdr;
const color = req.body.color; const color = req.body.color;
const passphrase = req.body.passphrase;
let createType: CreateCalendarTypeCommand = { let createType: CreateCalendarTypeCommand = {
type, type,
nscdr, nscdr,
color, color,
passphrase,
}; };
let id = await CalendarTypeCommandHandler.create(createType); let id = await CalendarTypeCommandHandler.create(createType);
@ -154,12 +156,14 @@ export async function updateCalendarType(req: Request, res: Response): Promise<a
const type = req.body.type; const type = req.body.type;
const nscdr = req.body.nscdr; const nscdr = req.body.nscdr;
const color = req.body.color; const color = req.body.color;
const passphrase = req.body.passphrase;
let updateType: UpdateCalendarTypeCommand = { let updateType: UpdateCalendarTypeCommand = {
id, id,
type, type,
nscdr, nscdr,
color, color,
passphrase,
}; };
await CalendarTypeCommandHandler.update(updateType); await CalendarTypeCommandHandler.update(updateType);

View file

@ -4,29 +4,60 @@ import CalendarTypeService from "../service/calendarTypeService";
import { calendar } from "../entity/calendar"; import { calendar } from "../entity/calendar";
import { createEvents } from "ics"; import { createEvents } from "ics";
import moment from "moment"; import moment from "moment";
import InternalException from "../exceptions/internalException";
import CalendarFactory from "../factory/admin/calendar";
/** /**
* @description get all calendar items by types or nscdr * @description get all calendar items by types or nscdr
* @summary passphrase is passed as value pair like `type:passphrase`
* @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<*>}
*/ */
export async function getCalendarItemsByTypes(req: Request, res: Response): Promise<any> { export async function getCalendarItemsByTypes(req: Request, res: Response): Promise<any> {
let types = Array.isArray(req.query.types) ? req.query.types : [req.query.types]; 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`)");
}
types = types.filter((t) => t);
let items: Array<calendar> = []; let items: Array<calendar> = [];
if (types.length == 0) { if (types.length != 0) {
let typeIds = await CalendarTypeService.getByTypes(types as Array<string>); let typeIds = await CalendarTypeService.getByTypes((types as Array<string>).map((t) => t.split(":")[0]));
typeIds = typeIds.filter(
(ti) =>
ti.passphrase == null ||
ti.passphrase == "" ||
ti.passphrase == (types as Array<string>).find((t) => t.includes(ti.type)).split(":")[1]
);
items = await CalendarService.getByTypes(typeIds.map((t) => t.id)); items = await CalendarService.getByTypes(typeIds.map((t) => t.id));
} else { } else {
items = await CalendarService.getByTypeNSCDR(); items = await CalendarService.getByTypeNSCDR();
} }
if (output == "json") {
res.json(CalendarFactory.mapToBase(items));
} else {
let events = createEvents( let events = createEvents(
items.map((i) => ({ items.map((i) => ({
calName: process.env.CLUB_NAME, calName: process.env.CLUB_NAME,
uid: i.id, uid: i.id,
sequence: 1, 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) start: moment(i.starttime)
.format("YYYY-M-D-H-m") .format("YYYY-M-D-H-m")
.split("-") .split("-")
@ -35,6 +66,7 @@ export async function getCalendarItemsByTypes(req: Request, res: Response): Prom
.format("YYYY-M-D-H-m") .format("YYYY-M-D-H-m")
.split("-") .split("-")
.map((a) => parseInt(a)) as [number, number, number, number, number], .map((a) => parseInt(a)) as [number, number, number, number, number],
}),
title: i.title, title: i.title,
description: i.content, description: i.content,
location: i.location, location: i.location,
@ -64,3 +96,4 @@ export async function getCalendarItemsByTypes(req: Request, res: Response): Prom
res.type("ics").send(events.value); res.type("ics").send(events.value);
} }
}

View file

@ -43,6 +43,7 @@ import { Calendar1729947763295 } from "./migrations/1729947763295-calendar";
import { reset } from "./entity/reset"; import { reset } from "./entity/reset";
import { ResetToken1732358596823 } from "./migrations/1732358596823-resetToken"; import { ResetToken1732358596823 } from "./migrations/1732358596823-resetToken";
import { SMSAlarming1732696919191 } from "./migrations/1732696919191-SMSAlarming"; import { SMSAlarming1732696919191 } from "./migrations/1732696919191-SMSAlarming";
import { SecuringCalendarType1733249553766 } from "./migrations/1733249553766-securingCalendarType";
const dataSource = new DataSource({ const dataSource = new DataSource({
type: DB_TYPE as any, type: DB_TYPE as any,
@ -96,6 +97,7 @@ const dataSource = new DataSource({
Calendar1729947763295, Calendar1729947763295,
ResetToken1732358596823, ResetToken1732358596823,
SMSAlarming1732696919191, SMSAlarming1732696919191,
SecuringCalendarType1733249553766,
], ],
migrationsRun: true, migrationsRun: true,
migrationsTransactionMode: "each", migrationsTransactionMode: "each",

View file

@ -15,6 +15,9 @@ export class calendarType {
@Column({ type: "varchar", length: 255 }) @Column({ type: "varchar", length: 255 })
color: string; color: string;
@Column({ type: "varchar", length: 255, nullable: true, default: null })
passphrase: string | null;
@OneToMany(() => calendar, (c) => c.type, { @OneToMany(() => calendar, (c) => c.type, {
nullable: false, nullable: false,
onDelete: "RESTRICT", onDelete: "RESTRICT",

View file

@ -13,6 +13,7 @@ export default abstract class CalendarTypeFactory {
type: record.type, type: record.type,
nscdr: record.nscdr, nscdr: record.nscdr,
color: record.color, color: record.color,
passphrase: record.passphrase,
}; };
} }

View file

@ -0,0 +1,20 @@
import { MigrationInterface, QueryRunner, TableColumn } from "typeorm";
export class SecuringCalendarType1733249553766 implements MigrationInterface {
name = "SecuringCalendarType1733249553766";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.addColumns("calendar_type", [
new TableColumn({
name: "passphrase",
type: "varchar",
length: "255",
isNullable: true,
}),
]);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn("calendar_type", "passphrase");
}
}

View file

@ -3,4 +3,5 @@ export interface CalendarTypeViewModel {
type: string; type: string;
nscdr: boolean; nscdr: boolean;
color: string; color: string;
passphrase: string | null;
} }