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"> <script setup lang="ts">
import FullCalendar from "@fullcalendar/vue3"; import FullCalendar from "@fullcalendar/vue3";
@@ -9,7 +27,7 @@ import interactionPlugin from "@fullcalendar/interaction";
import timeGridPlugin from "@fullcalendar/timegrid"; import timeGridPlugin from "@fullcalendar/timegrid";
import iCalenderPlugin from "@fullcalendar/icalendar"; import iCalenderPlugin from "@fullcalendar/icalendar";
import router from "@/router"; import router from "@/router";
import { formatYearMonthDay } from "@/helpers/dates.ts"; import { formatYearMonthDay, removeTZ } from "@/helpers/dates.ts";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useQuery } from "@tanstack/vue-query"; import { useQuery } from "@tanstack/vue-query";
import tokenStore from "@/store/tokenStore.ts"; import tokenStore from "@/store/tokenStore.ts";
@@ -29,42 +47,26 @@ const op = ref();
const clickedEvent = ref(); const clickedEvent = ref();
const toggle = (info: EventClickArg) => { 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) { if (op.value.visible) {
clickedEvent.value = null; clickedEvent.value = null;
op.value.hide(); op.value.hide();
return; return;
} else { } 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 { export function formatYearMonthDay(date: Date): string {
return date.toISOString().split("T")[0].replace(/-/g, ""); 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 ICAL from "ical.js";
import { CalendarComponent } from "ical"; import { CalendarComponent } from "ical";
@@ -7,7 +23,7 @@ import { CalendarComponent } from "ical";
* @param color Color code for the event * @param color Color code for the event
*/ */
export interface ColorDistinctionEvent { export interface ColorDistinctionEvent {
title: string; summary: string;
color: string; color: string;
} }
@@ -23,7 +39,7 @@ export function parseICalData(icalData: string | undefined): CalendarComponent[]
const jCalData = ICAL.parse(icalData); const jCalData = ICAL.parse(icalData);
const comp = new ICAL.Component(jCalData); const comp = new ICAL.Component(jCalData);
const vEvents = comp.getAllSubcomponents('vevent'); const vEvents = comp.getAllSubcomponents('vevent');
const colorDistinctionEvents = extracted(vEvents); const colorDistinctionEvents = extractedColorizedEvents(vEvents);
return vEvents.map((vevent: CalendarComponent) => { return vEvents.map((vevent: CalendarComponent) => {
const event = new ICAL.Event(vevent); const event = new ICAL.Event(vevent);
@@ -34,7 +50,7 @@ export function parseICalData(icalData: string | undefined): CalendarComponent[]
end: event.endDate.toJSDate(), end: event.endDate.toJSDate(),
notes: event.description, notes: event.description,
allDay: event.startDate.isDate, 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, id: event.uid,
location: event.location, location: event.location,
}; };
@@ -47,21 +63,33 @@ export function parseICalData(icalData: string | undefined): CalendarComponent[]
* @param vEvents Array of calendar components * @param vEvents Array of calendar components
* @returns Array of objects with event name and color * @returns Array of objects with event name and color
*/ */
function extracted(vEvents: CalendarComponent[]): ColorDistinctionEvent[] { function extractedColorizedEvents(vEvents: CalendarComponent[]): ColorDistinctionEvent[] {
// filter vevents to get all unique event names return colorizeEvents(filterEventsDistinct(vEvents));
const distinctEvents = vEvents.filter((vevent: CalendarComponent, index: number, self: CalendarComponent[]) => { }
const event = new ICAL.Event(vevent);
/**
* 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) => { return self.findIndex((v) => {
const e = new ICAL.Event(v); return v.summary === vevent.summary;
return e.summary === event.summary;
}) === index; }) === 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); * Assigns a color to each event
// map event name to a color for color coding css * @param vEvents Array of calendar components
// like var(--htwk-rot-700) * @returns Array of objects with event name and color
*/
function colorizeEvents(vEvents: CalendarComponent[]): ColorDistinctionEvent[] {
return vEvents.map((vevent: CalendarComponent) => {
const colors: string[] = [ const colors: string[] = [
"var(--htwk-rot-200)", "var(--htwk-rot-200)",
"var(--htwk-gruen-300)", "var(--htwk-gruen-300)",
@@ -76,14 +104,19 @@ function extracted(vEvents: CalendarComponent[]): ColorDistinctionEvent[] {
"var(--htwk-blau-200)" "var(--htwk-blau-200)"
]; ];
// give each event a color based on its name ascending const randomColor = colors[vEvents.findIndex((e: CalendarComponent) => {
const randomColor = colors[distinctEvents.findIndex((e: CalendarComponent) => { return e.summary === vevent.summary?? "";
const ev = new ICAL.Event(e);
return ev.summary === event.summary;
}) % colors.length]; }) % colors.length];
return { return {
title: event.summary, summary: vevent.summary?? "",
color: randomColor 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 tokenRegex = /^[a-z0-9]{15}$/;
const tokenUriRegex = /[?&]token=([a-z0-9]{15})(?:&|$)/; const tokenUriRegex = /[?&]token=([a-z0-9]{15})(?:&|$)/;