test:#13 added tests and added licence

This commit is contained in:
Elmar Kresse
2024-06-10 10:36:48 +02:00
parent f68d4ae445
commit ee0894d048
5 changed files with 246 additions and 49 deletions

View File

@ -1,3 +1,21 @@
<!--
Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
Copyright (C) 2024 HTWKalender support@htwkalender.de
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<script setup lang="ts">
import FullCalendar from "@fullcalendar/vue3";
@ -9,7 +27,7 @@ import interactionPlugin from "@fullcalendar/interaction";
import timeGridPlugin from "@fullcalendar/timegrid";
import iCalenderPlugin from "@fullcalendar/icalendar";
import router from "@/router";
import { formatYearMonthDay } from "@/helpers/dates.ts";
import { formatYearMonthDay, removeTZ } from "@/helpers/dates.ts";
import { useI18n } from "vue-i18n";
import { useQuery } from "@tanstack/vue-query";
import tokenStore from "@/store/tokenStore.ts";
@ -29,42 +47,26 @@ const op = ref();
const clickedEvent = ref();
const toggle = (info: EventClickArg) => {
const start = !info.event.start ? "" : removeTZ(info.event.start);
const end = !info.event.end ? "" : removeTZ(info.event.end);
if (op.value.visible) {
clickedEvent.value = null;
op.value.hide();
return;
} else {
clickedEvent.value = {
title: info.event._def.title,
start: start,
end: end,
notes: info.event._def.extendedProps.notes,
allDay: info.event._def.allDay,
location: info.event._def.extendedProps.location,
};
op.value.show(info.jsEvent);
op.value.target = info.el;
const start = info.event.start
const end = info.event.end
if (!start || !end) {
clickedEvent.value = {
title: info.event._def.title,
start: "",
end: "",
notes: info.event._def.extendedProps.notes,
allDay: info.event._def.allDay,
location: info.event._def.extendedProps.location,
};
op.value.show(info.jsEvent);
op.value.target = info.el;
} else {
const timeZoneOffsetStart = start.getTimezoneOffset() * 60000;
const timeZoneOffsetEnd = end.getTimezoneOffset() * 60000;
clickedEvent.value = {
title: info.event._def.title,
start: new Date(start.getTime() + timeZoneOffsetStart),
end: new Date(end.getTime() + timeZoneOffsetEnd),
notes: info.event._def.extendedProps.notes,
allDay: info.event._def.allDay,
location: info.event._def.extendedProps.location,
};
op.value.show(info.jsEvent);
op.value.target = info.el;
}
}

View File

@ -22,3 +22,8 @@
export function formatYearMonthDay(date: Date): string {
return date.toISOString().split("T")[0].replace(/-/g, "");
}
export function removeTZ(date: Date): Date {
return new Date(date.getTime() + date.getTimezoneOffset() * 60000)
}

View File

@ -0,0 +1,141 @@
//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
//Copyright (C) 2024 HTWKalender support@htwkalender.de
//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU Affero General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU Affero General Public License for more details.
//You should have received a copy of the GNU Affero General Public License
//along with this program. If not, see <https://www.gnu.org/licenses/>.
import { expect, test } from "vitest";
import { exportedForTesting } from "@/helpers/ical.ts";
import { CalendarComponent } from "ical";
// colorizeEvents has only the function to colorize the events that are passed to it
test("colorizeEventsSameSummary", () => {
const events: CalendarComponent[] =
[
{
type: "VEVENT",
summary: "Operations Research",
},
{
type: "VEVENT",
summary: "Operations Research",
},
];
expect(exportedForTesting.colorizeEvents(
events
)
).toEqual([{ summary: "Operations Research", color: "var(--htwk-rot-200)" },{ summary: "Operations Research", color: "var(--htwk-rot-200)" }]);
}
);
test("colorizeEventsDifferentSummary", () => {
const events: CalendarComponent[] =
[
{
type: "VEVENT",
summary: "Algorithmische Mathematik",
},
{
type: "VEVENT",
summary: "Funktionale Programmierung",
},
];
expect(exportedForTesting.colorizeEvents(
events
)
).toEqual([{ summary: "Algorithmische Mathematik", color: "var(--htwk-rot-200)" },{ summary: "Funktionale Programmierung", color: "var(--htwk-gruen-300)" }]);
}
);
test("filterEventsDistinct", () => {
const events: CalendarComponent[] =
[
{
type: "VEVENT",
summary: "Operations Research",
},
{
type: "VEVENT",
summary: "Operations Research",
},
];
expect(exportedForTesting.filterEventsDistinct(
events
)
).toEqual([{ type: "VEVENT", summary: "Operations Research" }]);
});
test("filterEventsDistinctDifferentSummary", () => {
const events: CalendarComponent[] =
[
{
type: "VEVENT",
summary: "Algorithmische Mathematik",
},
{
type: "VEVENT",
summary: "Funktionale Programmierung",
},
];
expect(exportedForTesting.filterEventsDistinct(
events
)
).toEqual(events);
});
test("extractedColorizedEvents", () => {
const events: CalendarComponent[] =
[
{
type: "VEVENT",
summary: "Operations Research",
},
{
type: "VEVENT",
summary: "Operations Research",
},
];
expect(exportedForTesting.extractedColorizedEvents(
events
)
).toEqual([{ summary: "Operations Research", color: "var(--htwk-rot-200)" }]);
});
test("extractedColorizedEventsDifferentSummary", () => {
const events: CalendarComponent[] =
[
{
type: "VEVENT",
summary: "Algorithmische Mathematik",
},
{
type: "VEVENT",
summary: "Funktionale Programmierung",
},
];
expect(exportedForTesting.extractedColorizedEvents(
events
)
).toEqual([{ summary: "Algorithmische Mathematik", color: "var(--htwk-rot-200)" },{ summary: "Funktionale Programmierung", color: "var(--htwk-gruen-300)" }]);
});

View File

@ -1,3 +1,19 @@
//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
//Copyright (C) 2024 HTWKalender support@htwkalender.de
//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU Affero General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU Affero General Public License for more details.
//You should have received a copy of the GNU Affero General Public License
//along with this program. If not, see <https://www.gnu.org/licenses/>.
import ICAL from "ical.js";
import { CalendarComponent } from "ical";
@ -7,7 +23,7 @@ import { CalendarComponent } from "ical";
* @param color Color code for the event
*/
export interface ColorDistinctionEvent {
title: string;
summary: string;
color: string;
}
@ -23,7 +39,7 @@ export function parseICalData(icalData: string | undefined): CalendarComponent[]
const jCalData = ICAL.parse(icalData);
const comp = new ICAL.Component(jCalData);
const vEvents = comp.getAllSubcomponents('vevent');
const colorDistinctionEvents = extracted(vEvents);
const colorDistinctionEvents = extractedColorizedEvents(vEvents);
return vEvents.map((vevent: CalendarComponent) => {
const event = new ICAL.Event(vevent);
@ -34,7 +50,7 @@ export function parseICalData(icalData: string | undefined): CalendarComponent[]
end: event.endDate.toJSDate(),
notes: event.description,
allDay: event.startDate.isDate,
color: colorDistinctionEvents.find((e: ColorDistinctionEvent) => e.title === event.summary)?.color,
color: colorDistinctionEvents.find((e: ColorDistinctionEvent) => e.summary === event.summary)?.color,
id: event.uid,
location: event.location,
};
@ -47,21 +63,33 @@ export function parseICalData(icalData: string | undefined): CalendarComponent[]
* @param vEvents Array of calendar components
* @returns Array of objects with event name and color
*/
function extracted(vEvents: CalendarComponent[]): ColorDistinctionEvent[] {
// filter vevents to get all unique event names
const distinctEvents = vEvents.filter((vevent: CalendarComponent, index: number, self: CalendarComponent[]) => {
const event = new ICAL.Event(vevent);
function extractedColorizedEvents(vEvents: CalendarComponent[]): ColorDistinctionEvent[] {
return colorizeEvents(filterEventsDistinct(vEvents));
}
/**
* Filters out duplicate events
* @param vEvents Array of calendar components
* @returns Array of calendar components without duplicates
*/
function filterEventsDistinct(vEvents: CalendarComponent[]): CalendarComponent[] {
return vEvents.filter((vevent: CalendarComponent, index: number, self: CalendarComponent[]) => {
return self.findIndex((v) => {
const e = new ICAL.Event(v);
return e.summary === event.summary;
return v.summary === vevent.summary;
}) === index;
});
}
//create dynamic color distinctionEvents map that will be used to color code events
return distinctEvents.map((vevent: CalendarComponent) => {
const event = new ICAL.Event(vevent);
// map event name to a color for color coding css
// like var(--htwk-rot-700)
/**
* Assigns a color to each event
* @param vEvents Array of calendar components
* @returns Array of objects with event name and color
*/
function colorizeEvents(vEvents: CalendarComponent[]): ColorDistinctionEvent[] {
return vEvents.map((vevent: CalendarComponent) => {
const colors: string[] = [
"var(--htwk-rot-200)",
"var(--htwk-gruen-300)",
@ -76,14 +104,19 @@ function extracted(vEvents: CalendarComponent[]): ColorDistinctionEvent[] {
"var(--htwk-blau-200)"
];
// give each event a color based on its name ascending
const randomColor = colors[distinctEvents.findIndex((e: CalendarComponent) => {
const ev = new ICAL.Event(e);
return ev.summary === event.summary;
const randomColor = colors[vEvents.findIndex((e: CalendarComponent) => {
return e.summary === vevent.summary?? "";
}) % colors.length];
return {
title: event.summary,
summary: vevent.summary?? "",
color: randomColor
};
});
}
export const exportedForTesting = {
extractedColorizedEvents,
filterEventsDistinct,
colorizeEvents
};

View File

@ -1,3 +1,19 @@
//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
//Copyright (C) 2024 HTWKalender support@htwkalender.de
//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU Affero General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU Affero General Public License for more details.
//You should have received a copy of the GNU Affero General Public License
//along with this program. If not, see <https://www.gnu.org/licenses/>.
const tokenRegex = /^[a-z0-9]{15}$/;
const tokenUriRegex = /[?&]token=([a-z0-9]{15})(?:&|$)/;