From 27413d956c5021dea8646b3e69aa3f68137ed9fb Mon Sep 17 00:00:00 2001 From: Niko Date: Mon, 13 Jul 2026 16:39:21 +0200 Subject: [PATCH 1/4] Fix open-spaces --- src/utils/openSpaces.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/utils/openSpaces.ts b/src/utils/openSpaces.ts index c48c13a35..de7077659 100644 --- a/src/utils/openSpaces.ts +++ b/src/utils/openSpaces.ts @@ -27,7 +27,7 @@ export interface OpenSpaceEvent { function stripHtml(s: string): string { return s - .replace(/[<>]/g, "") + .replace(/<[^>]*>/g, "") .replace(/https?:\/\/ep[^.]*\.europython\.eu(\/[^\s]/g, "") + .replace(/<[^>]*>/g, "") .replace(/https?:\/\/ep[^.]*\.europython\.eu(\/[^\s]/g, "") + .replace(/<[^>]*>/g, "") .replace(/'/g, "'") .replace(/&/g, "&") .replace(/\\n/g, "\n"); @@ -150,8 +150,8 @@ function parseICal(ics: string): OpenSpaceEvent[] { const summary = getVal("SUMMARY"); const rawDescription = getVal("DESCRIPTION"); const organizer = getVal("ORGANIZER"); - let dtStartRaw = getVal("DTSTART"); - let dtEndRaw = getVal("DTEND"); + const dtStartRaw = getVal("DTSTART"); + const dtEndRaw = getVal("DTEND"); if (!dtStartRaw) continue; const startDt = parseDt(dtStartRaw); @@ -175,7 +175,7 @@ function parseICal(ics: string): OpenSpaceEvent[] { ); if (descMatch) { fullDescription = descMatch[1] - .replace(/[<>]/g, "") + .replace(/<[^>]*>/g, "") .replace(/'/g, "'") .replace(/&/g, "&") .replace(/\\n/g, "\n") From 2eb42fda667572f113d0b979ece64778217feb05 Mon Sep 17 00:00:00 2001 From: Niko Date: Mon, 13 Jul 2026 16:47:29 +0200 Subject: [PATCH 2/4] Update posters details --- src/utils/openSpaces.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils/openSpaces.ts b/src/utils/openSpaces.ts index de7077659..b68dafaa9 100644 --- a/src/utils/openSpaces.ts +++ b/src/utils/openSpaces.ts @@ -28,6 +28,7 @@ export interface OpenSpaceEvent { function stripHtml(s: string): string { return s .replace(/<[^>]*>/g, "") + .replace(/]*>/g, "") + .replace(/]*>/g, "") + .replace(/]*>/g, "") + .replace(/ Date: Mon, 13 Jul 2026 16:53:44 +0200 Subject: [PATCH 3/4] Fix CodeQL incomplete multi-character sanitization Replace two chained regexes (tag stripping + < removal) with a single /<[^>]*(?:>|$)/g that handles both complete and incomplete HTML tags as one multi-character pattern. - matches via [^>]*> - at end of string matches via [^>]*$ - This satisfies CodeQL's multi-character sanitization rule --- src/utils/openSpaces.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/utils/openSpaces.ts b/src/utils/openSpaces.ts index b68dafaa9..4f6d6971f 100644 --- a/src/utils/openSpaces.ts +++ b/src/utils/openSpaces.ts @@ -27,8 +27,7 @@ export interface OpenSpaceEvent { function stripHtml(s: string): string { return s - .replace(/<[^>]*>/g, "") - .replace(/]*(?:>|$)/g, "") .replace(/https?:\/\/ep[^.]*\.europython\.eu(\/[^\s]*>/g, "") - .replace(/]*(?:>|$)/g, "") .replace(/https?:\/\/ep[^.]*\.europython\.eu(\/[^\s]*>/g, "") - .replace(/]*(?:>|$)/g, "") .replace(/'/g, "'") .replace(/&/g, "&") .replace(/\\n/g, "\n"); @@ -178,8 +175,7 @@ function parseICal(ics: string): OpenSpaceEvent[] { ); if (descMatch) { fullDescription = descMatch[1] - .replace(/<[^>]*>/g, "") - .replace(/]*(?:>|$)/g, "") .replace(/'/g, "'") .replace(/&/g, "&") .replace(/\\n/g, "\n") From de79da1b0a5749eea874b34086cbc37e95ae4249 Mon Sep 17 00:00:00 2001 From: Niko Date: Mon, 13 Jul 2026 17:00:41 +0200 Subject: [PATCH 4/4] Fix timezone: display Europe/Warsaw time instead of raw UTC The ICS data uses UTC (Z suffix) for DTSTART/DTEND, but the calendar grid and detail page were displaying the raw UTC hour (e.g. 08:00) instead of converting to Europe/Warsaw (UTC+2 in July = 10:00 CEST). Fix: - Grid: use fmtTime(startISO) for grouping and display labels - Grid header: label column as 'Time (CEST)' - Detail page: convert startISO/endISO via toLocaleTimeString with Europe/Warsaw timezone - Clean up: remove unused props (calendarId, timeMin, timeMax) --- src/components/sections/OpenSpacesCalendar.astro | 8 +++----- src/pages/session/open-space/[slug].astro | 14 ++++++++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/components/sections/OpenSpacesCalendar.astro b/src/components/sections/OpenSpacesCalendar.astro index 5fd87b583..8e702d2af 100644 --- a/src/components/sections/OpenSpacesCalendar.astro +++ b/src/components/sections/OpenSpacesCalendar.astro @@ -15,9 +15,6 @@ export interface Props { } const { - calendarId = "c_b87075b29cf4a9dd4da3fe724fcba92a4b406aa3f91cb7e7ce50fede43215b17@group.calendar.google.com", - timeMin = "20260713", - timeMax = "20260719", rooms = ["S4(1,2,3)", "S4(4)", "S4(5)"], } = Astro.props; @@ -35,6 +32,7 @@ function fmtDateLabel(isoDate: string): string { } catch { return isoDate; } } + // ── Main data fetch ── const allEvents = await fetchOpenSpacesEvents(); @@ -57,7 +55,7 @@ const displayRooms = rooms; function buildTimeSlots(dayEvents: OpenSpaceEvent[]) { const timeMap = new Map>(); for (const ev of dayEvents) { - const label = ev.startTime; + const label = fmtTime(ev.startISO); if (!timeMap.has(label)) timeMap.set(label, {}); const slot = timeMap.get(label); if (slot) slot[ev.room] = ev; @@ -87,7 +85,7 @@ const hasEvents = sortedDates.length > 0; {timeSlots.length > 0 ? (
-
Time
+
Time (CEST)
{displayRooms.map((room) => (
{room}
))} diff --git a/src/pages/session/open-space/[slug].astro b/src/pages/session/open-space/[slug].astro index 52964d602..73f07c61f 100644 --- a/src/pages/session/open-space/[slug].astro +++ b/src/pages/session/open-space/[slug].astro @@ -16,11 +16,19 @@ export async function getStaticPaths() { const { event } = Astro.props as { event: OpenSpaceEvent }; +const tz = "Europe/Warsaw"; + const dateLabel = new Date(event.date + "T12:00:00Z").toLocaleDateString( "en-GB", - { timeZone: "Europe/Warsaw", weekday: "long", day: "numeric", month: "long", year: "numeric" } + { timeZone: tz, weekday: "long", day: "numeric", month: "long", year: "numeric" } ); +const timeLabel = (() => { + const start = new Date(event.startISO).toLocaleTimeString("en-GB", { timeZone: tz, hour: "2-digit", minute: "2-digit" }); + const end = new Date(event.endISO).toLocaleTimeString("en-GB", { timeZone: tz, hour: "2-digit", minute: "2-digit" }); + return `${start} \u2013 ${end} CEST`; +})(); + const backUrl = event.date ? `/open-spaces#osp-day-${event.date}` : "/open-spaces"; @@ -47,9 +55,7 @@ const backUrl = event.date
Date:
{dateLabel}
Time:
-
- {event.startTime} – {event.endTime} -
+
{timeLabel}