From 89f6c9198dd6e9298e3ecb049b4b8b552688b1ea Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 3 May 2026 15:41:05 +0200 Subject: [PATCH 01/38] Korrigiere Datum des Neujahrsempfangs und entferne kaputte rrule. Der dtstart stand auf 2025 statt 2026, und die rrule "FREQ=MOTHLY" enthielt einen Tippfehler, sodass das Event nicht im Kalender auftauchte. Der Neujahrsempfang ist ein Einzeltermin und braucht keine rrule. Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Hauke Mehrtens --- content/veranstaltungen/neujahresempfang.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/content/veranstaltungen/neujahresempfang.md b/content/veranstaltungen/neujahresempfang.md index 6bcd354..9a97796 100644 --- a/content/veranstaltungen/neujahresempfang.md +++ b/content/veranstaltungen/neujahresempfang.md @@ -2,9 +2,8 @@ title: "Neujahresempfang" subtitle: "#NJE 26" date: 2025-03-05T18:00:00+02:00 -dtstart: 20250523T180000 -dtend: 20250524T100000 -rrule: "FREQ=MOTHLY;BYDAY=4SA;WKST=MO" +dtstart: 20260523T180000 +dtend: 20260524T100000 menu: main: parent: "Veranstaltungen" From b27b3899ce42250ba2a19af30354b4da12f649b2 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 3 May 2026 15:37:32 +0200 Subject: [PATCH 02/38] Korrigiere Link auf Club Discordia und Rechtschreibfehler. Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Hauke Mehrtens --- content/veranstaltungen/bastelabend.md | 4 ++-- content/veranstaltungen/spieleabend.md | 4 ++-- content/veranstaltungen/subbotnik.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/content/veranstaltungen/bastelabend.md b/content/veranstaltungen/bastelabend.md index 5f3d995..c787c17 100644 --- a/content/veranstaltungen/bastelabend.md +++ b/content/veranstaltungen/bastelabend.md @@ -26,7 +26,7 @@ draft: true {{< alert "circle-info" >}} -Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/page/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. +Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/veranstaltungen/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. -Generell sind aber alle, die schonmal im Club waren, herzlich eingeladen, an den Bastelabenden vorbeizukommen. +Generell sind aber alle, die schon mal im Club waren, herzlich eingeladen, an den Bastelabenden vorbeizukommen. {{< /alert >}} diff --git a/content/veranstaltungen/spieleabend.md b/content/veranstaltungen/spieleabend.md index e1122f9..ab3d120 100644 --- a/content/veranstaltungen/spieleabend.md +++ b/content/veranstaltungen/spieleabend.md @@ -16,7 +16,7 @@ tag: ["Veranstaltung"] **Jeden 2. und 4. Samstag im Monat ist ab 17 Uhr Spieleabend im Club.** {{< alert "circle-info" >}} -Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/page/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. +Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/veranstaltungen/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. -Generell sind aber alle, die schonmal im Club waren, herzlich eingeladen, an den Spieleabenden vorbeizukommen. +Generell sind aber alle, die schon mal im Club waren, herzlich eingeladen, an den Spieleabenden vorbeizukommen. {{< /alert >}} diff --git a/content/veranstaltungen/subbotnik.md b/content/veranstaltungen/subbotnik.md index 5e86aa2..a520035 100644 --- a/content/veranstaltungen/subbotnik.md +++ b/content/veranstaltungen/subbotnik.md @@ -23,8 +23,8 @@ Der Begriff [Subbotnik](https://de.wikipedia.org/wiki/Subbotnik) ist eine in Sow --- {{< alert "circle-info" >}} -Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/page/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. +Wenn ihr neu seid und den CCCB zum ersten Mal besuchen wollt, kommt am besten an einem Donnerstag zum [Club Discordia](/veranstaltungen/clubdiscordia/), da samstags nicht immer genug Leute da sind, um euch zu empfangen. -Generell sind aber alle, die schonmal im Club waren, herzlich eingeladen am Subbotnik vorbeizukommen und mitzuhelfen. +Generell sind aber alle, die schon mal im Club waren, herzlich eingeladen am Subbotnik vorbeizukommen und mitzuhelfen. {{< /alert >}} From aebd59d283308838cc3e99cadfe7d946b5632880 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 3 May 2026 15:12:22 +0200 Subject: [PATCH 03/38] =?UTF-8?q?OpenWrt=20Stammtisch:=20Stelle=20auf=20vi?= =?UTF-8?q?ertelj=C3=A4hrlichen=20Rhythmus=20um.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Das Treffen findet ab November 2025 nur noch jeden 3. Mittwoch im Februar, Mai, August und November statt. Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Hauke Mehrtens --- content/veranstaltungen/openwrt.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/veranstaltungen/openwrt.md b/content/veranstaltungen/openwrt.md index c2e66e8..282c130 100644 --- a/content/veranstaltungen/openwrt.md +++ b/content/veranstaltungen/openwrt.md @@ -2,9 +2,9 @@ title: "OpenWrt" subtitle: "OpenWrt Stammtisch" date: 2025-01-08T20:00:00+02:00 -dtstart: 20250115T200000 -dtend: 20250115T230000 -rrule: "FREQ=MONTHLY;BYDAY=3WE;WKST=MO" +dtstart: 20251119T200000 +dtend: 20251119T230000 +rrule: "FREQ=MONTHLY;INTERVAL=3;BYDAY=3WE;WKST=MO" menu: main: parent: "Veranstaltungen" @@ -13,7 +13,7 @@ tag: ["Veranstaltung"] ![Verschiedene Platinen im CCCB](/img/club/42300970272_667569d239.jpg) -**Jeden 3. Mittwoch im Monat ab 20 Uhr** treffen sich die OpenWrt begeisterten und die es werden wollen zum OpenWrt Stammtisch im CCCB. +**Jeden 3. Mittwoch im Februar, Mai, August und November ab 20 Uhr** treffen sich die OpenWrt begeisterten und die es werden wollen zum OpenWrt Stammtisch im CCCB. Das OpenWrt Meetup richtet sich an alle die OpenWrt benutzen oder benutzen wollen aber auch Leute die an OpenWrt entwickeln. From 0b67ad4cfb42c83500b1703c7cd74cffa4ca9ffa Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 3 May 2026 16:35:17 +0200 Subject: [PATCH 04/38] =?UTF-8?q?Kalender-UI:=20Ber=C3=BCcksichtige=20INTE?= =?UTF-8?q?RVAL=20und=20DTSTART=20bei=20monatlichen=20RRULEs.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der JS-RRULE-Parser im Kalender ignorierte bisher INTERVAL=, sodass z.B. FREQ=MONTHLY;INTERVAL=3 als reines monatliches Event angezeigt wurde. Außerdem wurden monatliche Events auch in Monaten vor ihrem DTSTART angezeigt. Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Hauke Mehrtens --- assets/js/calendar.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/assets/js/calendar.js b/assets/js/calendar.js index 5aa9d6b..ffb3c7e 100644 --- a/assets/js/calendar.js +++ b/assets/js/calendar.js @@ -131,6 +131,12 @@ document.addEventListener('DOMContentLoaded', function() { else if (rruleStr.includes("FREQ=MONTHLY") && rruleStr.includes("BYDAY")) { const bydayMatch = rruleStr.match(/BYDAY=([^;]+)/); if (bydayMatch) { + const intervalMatch = rruleStr.match(/INTERVAL=(\d+)/); + const interval = intervalMatch ? parseInt(intervalMatch[1]) : 1; + const monthsFromStart = (year - startDate.getFullYear()) * 12 + (month - startDate.getMonth()); + if (monthsFromStart < 0 || monthsFromStart % interval !== 0) { + return []; + } const bydays = bydayMatch[1].split(','); const dayMap = { 'MO': 1, 'TU': 2, 'WE': 3, 'TH': 4, 'FR': 5, 'SA': 6, 'SU': 0 From c145161bc4e4447123633e92ad34f270f8ab8855 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 3 May 2026 16:42:30 +0200 Subject: [PATCH 05/38] =?UTF-8?q?README:=20Erkl=C3=A4re,=20wie=20man=20den?= =?UTF-8?q?=20Kalender=20lokal=20sieht.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `hugo serve` rendert die Tabelle „Nächste Veranstaltungen" auf der Startseite nicht — die wird erst durch `./build.sh` per sed in `public/index.html` eingefügt. Die README beschreibt jetzt den Build-und-Servieren-Workflow inklusive Python-Abhängigkeiten und benötigtem Locale. Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Hauke Mehrtens --- README.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 86698bc..3b0af0f 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,24 @@ This is the website of the CCCB. 5. Point your browser to: -To ready your site for upload, run `./build.sh`, which also generates `all.ics` -and adds the calendar table to `index.html`. -Every change you make on the project will be reflected in your browser -as long as `hugo serve` is running. +Every change you make on the project will be reflected in your browser as long +as `hugo serve` is running. + +The *"Nächste Veranstaltungen"* table on the home page is generated by +post-processing in `./build.sh`, not by Hugo, so it is **not** visible under +`hugo serve`. To preview the fully-built site (including the home-page +calendar), or to ready the site for upload, run: + +```shell +./build.sh +python3 -m http.server -d public 1313 +``` + +`build.sh` generates `all.ics` and replaces the `CALENDAR` placeholder in +`index.html` with the upcoming-events table. It depends on Python with the +`icalendar`, `python-dateutil`, and `pytz` packages, plus a `de_DE.UTF-8` +locale (used to format weekday names). Inside `nix develop` these are +provided automatically. To build with *nix*: `nix build '.?submodules=1#production-content'` From 430662fa4465c00b942ea7bd6c5a27c54b6b21d6 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 3 May 2026 15:56:32 +0200 Subject: [PATCH 06/38] =?UTF-8?q?F=C3=BCge=20DI.Day=20als=20Veranstaltung?= =?UTF-8?q?=20hinzu.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der Berliner Di.Day (Digital Independence Day) findet jeden ersten Sonntag im Monat im Wechsel zwischen CCCB (ungerade Monate) und xHain (gerade Monate) statt. Im Kalender erscheinen nur die CCCB-Termine. Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Hauke Mehrtens --- content/veranstaltungen/didit.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 content/veranstaltungen/didit.md diff --git a/content/veranstaltungen/didit.md b/content/veranstaltungen/didit.md new file mode 100644 index 0000000..707fe52 --- /dev/null +++ b/content/veranstaltungen/didit.md @@ -0,0 +1,20 @@ +--- +title: "Di.Day" +subtitle: "Digital Independence Day im CCCB" +date: 2026-01-04T12:23:00+01:00 +dtstart: 20260104T122300 +dtend: 20260104T174200 +rrule: "FREQ=MONTHLY;INTERVAL=2;BYDAY=1SU;WKST=MO" +menu: + main: + parent: "Veranstaltungen" +tag: ["Veranstaltung"] +--- + +**Jeden ersten Sonntag im Monat von 12:23 bis 17:42 Uhr** findet der Berliner Digital Independence Day statt. Der Veranstaltungsort wechselt monatlich zwischen den Räumen des CCCB (in den ungeraden Monaten Januar, März, Mai, …) und dem [xHain](https://x-hain.de/) (in den geraden Monaten). + +Der CCCB und das xHain beteiligen sich gemeinsam an der internationalen [Digital Independence Day](https://diday.org)-Initiative. Diese Graswurzelbewegung ruft dazu auf, zu demokratiefreundlichen digitalen Alternativen zu wechseln, um die Abhängigkeit von großen Technologiekonzernen zu verringern. + +Vor Ort gibt es praktische Hilfe beim Wechsel zu datenschutzfreundlichen Diensten, beim Einrichten von Linux oder beim Betrieb von Smartphones ohne große Tech-Konzerne. Egal ob Anfänger:in oder Fortgeschrittene:r. Kommt vorbei und bringt eure Geräte und Fragen mit. + +Weitere Informationen gibt es im [Ankündigungsbeitrag](https://berlin.ccc.de/post/2026/02/22/berlin-%23didit/). From f82df9e156fccefe27f270b5070adca9e2459e22 Mon Sep 17 00:00:00 2001 From: xengi Date: Sat, 9 May 2026 22:37:55 +0200 Subject: [PATCH 07/38] Update .forgejo/workflows/deploy.yaml Signed-off-by: xengi --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index 1b6cc42..edc6f77 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -2,7 +2,7 @@ name: deploy blog on: workflow_dispatch: schedule: - - cron: '0 10 * * 3' # at 10:00 on wednesday + - cron: '0 10 * * *' # at 10:00 on wednesday push: branches: - staging From 8e280c350b1806bbb4e2f1f355bf64ca15e0921b Mon Sep 17 00:00:00 2001 From: xengi Date: Sun, 10 May 2026 15:18:56 +0200 Subject: [PATCH 08/38] Update .forgejo/workflows/deploy.yaml Signed-off-by: xengi --- .forgejo/workflows/deploy.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index 414eea3..b0b9a6c 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -1,6 +1,8 @@ name: deploy blog on: workflow_dispatch: + schedule: + - cron: '0 10 * * *' # daily at 10:00 push: branches: - staging From 781bda1674b8e515ffeba20e53343b9f28fd630d Mon Sep 17 00:00:00 2001 From: Bruno Ranieri Date: Fri, 19 Jun 2026 00:47:25 +0200 Subject: [PATCH 09/38] Post DiDay 2026-07-05 --- .../post/2026-07-05-di_day/di_day_logo.png | Bin 0 -> 26481 bytes content/post/2026-07-05-di_day/index.md | 52 ++++++++++++++++++ content/veranstaltungen/didit.md | 2 +- 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 content/post/2026-07-05-di_day/di_day_logo.png create mode 100644 content/post/2026-07-05-di_day/index.md diff --git a/content/post/2026-07-05-di_day/di_day_logo.png b/content/post/2026-07-05-di_day/di_day_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c7a621b997f8396aa2c02e3a524d5bb4a00d8376 GIT binary patch literal 26481 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 literal 0 HcmV?d00001 diff --git a/content/post/2026-07-05-di_day/index.md b/content/post/2026-07-05-di_day/index.md new file mode 100644 index 0000000..7b44241 --- /dev/null +++ b/content/post/2026-07-05-di_day/index.md @@ -0,0 +1,52 @@ +--- +title: "Berlin #DIDit" +date: 2026-06-18T12:00:00+01:00 +showHero: false +tags: ["di.day", "Ankündigung"] +--- + +di.day Logo + +### Was? + +Am Sonntag, dem 5. Juli, öffnet der Chaos Computer Club Berlin e.V. wieder seine Türen zum DID. + +Zusammen mit dem [xHain hack+makespace](https://x-hain.de/) unterstützen wir auf dem Weg in die digitale Unabhängigkeit. + +Gemeinsam arbeiten wir daran, unsere digitale Souveränität zurückzugewinnen. +Statt Abhängigkeiten von großen Plattformen setzen wir auf offene Alternativen und selbstbestimmte digitale Werkzeuge. +So holen wir uns Schritt für Schritt die Kontrolle über unser digitales Leben zurück und beschreiten den Weg zur digitalen Unabhängigkeit. + +Ob du jetzt + +- von WhatsApp zu einer datenschutzfreundlichen Alternative wechseln möchtest, +- dein Smartphone gerne ohne Google oder Apple betreiben willst, +- oder auf deinem Notebook lieber Linux anstelle von Windows benutzen würdest, + +wir helfen euch dabei gerne. Bringt gerne auch eure Geräte dafür mit. + +Natürlich kannst du auch einfach nur so vorbeikommen und uns Fragen stellen. + +### Wo? + +**Marienstraße 11, 10117 Berlin** + +### Wann? + +**Sonntag, 5. Juli 2026** \ +**12:00 bis 16:00 Uhr** + +Schaut aber auch gerne bei der +[Veranstaltung](tbd) +von [Digital-Zebra](https://termine.di.day/organisation/digitalzebra) und +der [c-base](https://termine.di.day/organisation/cbase) vorbei. + +**Gemeinsam mehr erreichen** \ +Diese Veranstaltung ist Teil eines Netzwerks aus mehreren Organisationen und Initiativen in Berlin. +Wir unterstützen uns gegenseitig mit Kompetenz, Erfahrung und praktischer Hilfe. +Uns alle eint der Wunsch, Wissen zu teilen, voneinander zu lernen und solidarisch zusammenzuarbeiten. +Der DI.Day bildet dabei den gemeinsamen Rahmen, +in dem wir uns für digitale Selbstbestimmung und nachhaltige digitale Strukturen einsetzen. + +Schau deshalb gern auch bei den Veranstaltungen der anderen beteiligten Organisationen vorbei. +So entsteht ein vielfältiges Angebot, das Austausch, Vernetzung und gegenseitige Unterstützung lebendig macht. diff --git a/content/veranstaltungen/didit.md b/content/veranstaltungen/didit.md index 707fe52..b5badfc 100644 --- a/content/veranstaltungen/didit.md +++ b/content/veranstaltungen/didit.md @@ -17,4 +17,4 @@ Der CCCB und das xHain beteiligen sich gemeinsam an der internationalen [Digital Vor Ort gibt es praktische Hilfe beim Wechsel zu datenschutzfreundlichen Diensten, beim Einrichten von Linux oder beim Betrieb von Smartphones ohne große Tech-Konzerne. Egal ob Anfänger:in oder Fortgeschrittene:r. Kommt vorbei und bringt eure Geräte und Fragen mit. -Weitere Informationen gibt es im [Ankündigungsbeitrag](https://berlin.ccc.de/post/2026/02/22/berlin-%23didit/). +Weitere Informationen gibt es im [Ankündigungsbeitrag](https://berlin.ccc.de/post/2026/07/05/berlin-%23didit/). From 5cbeeab329620944f912b7aea98f5f2263b3f0db Mon Sep 17 00:00:00 2001 From: Bruno Ranieri Date: Fri, 19 Jun 2026 01:27:23 +0200 Subject: [PATCH 10/38] figure definition --- content/post/2026-07-05-di_day/index.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/content/post/2026-07-05-di_day/index.md b/content/post/2026-07-05-di_day/index.md index 7b44241..bbba31b 100644 --- a/content/post/2026-07-05-di_day/index.md +++ b/content/post/2026-07-05-di_day/index.md @@ -5,7 +5,14 @@ showHero: false tags: ["di.day", "Ankündigung"] --- -di.day Logo +{{< figure + src="di_day_logo.png" + title="DIDay" + alt="DIDay" + +>}} + + ### Was? From 175c15be11724e65c7eb753a2d03c1e1747d0359 Mon Sep 17 00:00:00 2001 From: Bruno Ranieri Date: Fri, 19 Jun 2026 01:35:40 +0200 Subject: [PATCH 11/38] wip 1 --- content/post/2026-07-05-di_day/index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/content/post/2026-07-05-di_day/index.md b/content/post/2026-07-05-di_day/index.md index bbba31b..2ccd6ff 100644 --- a/content/post/2026-07-05-di_day/index.md +++ b/content/post/2026-07-05-di_day/index.md @@ -9,7 +9,6 @@ tags: ["di.day", "Ankündigung"] src="di_day_logo.png" title="DIDay" alt="DIDay" - >}} From 936361815798a7ff5665edf2fc7e7ecd9f09aa21 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 3 May 2026 16:25:16 +0200 Subject: [PATCH 12/38] Behebe Layoutauswahl unter aktuellem Hugo. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die layouts/_default/*.calendar.html-Vorlagen werden in Hugo ≥0.158 fälschlich für die HTML-Ausgabe ausgewählt, sodass alle Sektions- und Einzelseiten VCALENDAR- statt HTML-Inhalt enthielten. Die Vorlagen waren ohnehin nie funktionsfähig (Warnung „found no layout file for calendar"); die ICS-Feeds liefern die abschnittsspezifischen Vorlagen unter layouts/{veranstaltungen,datengarten,page}/. list.xml.html bekommt aus demselben Grund die korrekte Endung .xml. tools/gen_upcoming.py vergleicht Datumsangaben jetzt zeitzonenneutral, damit Events mit Z-Suffix keinen TypeError auslösen. Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Hauke Mehrtens --- layouts/_default/baseof.calendar.html | 1 - layouts/_default/list.calendar.html | 21 ------------------- .../_default/{list.xml.html => list.xml.xml} | 0 layouts/_default/single.calendar.html | 21 ------------------- tools/gen_upcoming.py | 12 ++++++++++- 5 files changed, 11 insertions(+), 44 deletions(-) delete mode 100644 layouts/_default/baseof.calendar.html delete mode 100644 layouts/_default/list.calendar.html rename layouts/_default/{list.xml.html => list.xml.xml} (100%) delete mode 100644 layouts/_default/single.calendar.html diff --git a/layouts/_default/baseof.calendar.html b/layouts/_default/baseof.calendar.html deleted file mode 100644 index bddf04a..0000000 --- a/layouts/_default/baseof.calendar.html +++ /dev/null @@ -1 +0,0 @@ -{{ block "main" . }}{{ .Content }}{{ end }} diff --git a/layouts/_default/list.calendar.html b/layouts/_default/list.calendar.html deleted file mode 100644 index 3259690..0000000 --- a/layouts/_default/list.calendar.html +++ /dev/null @@ -1,21 +0,0 @@ -BEGIN:VCALENDAR -VERSION:2.0 -PRODID:-//CCCB//Calendar//DE -{{ with .Title }} -X-WR-CALNAME:{{ . }} -{{ end }} -CALSCALE:GREGORIAN -METHOD:PUBLISH -{{ range .Pages }} -{{ if .Date }} -BEGIN:VEVENT -UID:{{ .File.UniqueID }}@berlin.ccc.de -DTSTAMP:{{ .Date.Format "20060102T150405Z" }} -DTSTART:{{ .Date.Format "20060102T150405Z" }} -SUMMARY:{{ .Title }} -DESCRIPTION:{{ .Summary | plainify }} -URL:{{ .Permalink }} -END:VEVENT -{{ end }} -{{ end }} -END:VCALENDAR diff --git a/layouts/_default/list.xml.html b/layouts/_default/list.xml.xml similarity index 100% rename from layouts/_default/list.xml.html rename to layouts/_default/list.xml.xml diff --git a/layouts/_default/single.calendar.html b/layouts/_default/single.calendar.html deleted file mode 100644 index 5a22ec4..0000000 --- a/layouts/_default/single.calendar.html +++ /dev/null @@ -1,21 +0,0 @@ -BEGIN:VCALENDAR -VERSION:2.0 -PRODID:-//CCCB//Calendar//DE -{{ with .Title }} -X-WR-CALNAME:{{ . }} -{{ end }} -CALSCALE:GREGORIAN -METHOD:PUBLISH -{{ if .Date }} -BEGIN:VEVENT -UID:{{ .File.UniqueID }}@berlin.ccc.de -DTSTAMP:{{ .Date.Format "20060102T150405Z" }} -DTSTART:{{ .Date.Format "20060102T150405Z" }} -{{ with .Params.event.end }}DTEND:{{ dateFormat "20060102T150405Z" . }}{{ end }} -SUMMARY:{{ .Title }} -DESCRIPTION:{{ .Summary | plainify }} -URL:{{ .Permalink }} -{{ with .Params.location }}LOCATION:{{ . }}{{ end }} -END:VEVENT -{{ end }} -END:VCALENDAR diff --git a/tools/gen_upcoming.py b/tools/gen_upcoming.py index 0f69f6a..33b093d 100755 --- a/tools/gen_upcoming.py +++ b/tools/gen_upcoming.py @@ -3,13 +3,23 @@ import sys import logging import locale -from dateutil.parser import parse +from dateutil.parser import parse as _parse from datetime import datetime, timedelta from dateutil.rrule import rruleset, rrulestr import icalendar +def parse(value): + # Some templates emit DTSTART with a trailing "Z" (e.g. 20260507T190000Z) + # which produces tz-aware datetimes, while others emit naive local times. + # Normalize to naive so comparisons and sorting don't mix the two. + dt = _parse(value) + if dt.tzinfo is not None: + dt = dt.replace(tzinfo=None) + return dt + + def vevent_to_event(event, rrstart=None): if rrstart == None: begin = parse(event["DTSTART"].to_ical()) From bf1de4633ba28550d5bddcfeb00b89431e4ca008 Mon Sep 17 00:00:00 2001 From: Bruno Ranieri Date: Sat, 4 Jul 2026 23:32:57 +0200 Subject: [PATCH 13/38] remove did-post and update did-page --- .../post/2026-07-05-di_day/di_day_logo.png | Bin 26481 -> 0 bytes content/post/2026-07-05-di_day/index.md | 58 ------------------ content/veranstaltungen/didit.md | 10 +-- 3 files changed, 6 insertions(+), 62 deletions(-) delete mode 100644 content/post/2026-07-05-di_day/di_day_logo.png delete mode 100644 content/post/2026-07-05-di_day/index.md diff --git a/content/post/2026-07-05-di_day/di_day_logo.png b/content/post/2026-07-05-di_day/di_day_logo.png deleted file mode 100644 index c7a621b997f8396aa2c02e3a524d5bb4a00d8376..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26481 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 diff --git a/content/post/2026-07-05-di_day/index.md b/content/post/2026-07-05-di_day/index.md deleted file mode 100644 index 2ccd6ff..0000000 --- a/content/post/2026-07-05-di_day/index.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: "Berlin #DIDit" -date: 2026-06-18T12:00:00+01:00 -showHero: false -tags: ["di.day", "Ankündigung"] ---- - -{{< figure - src="di_day_logo.png" - title="DIDay" - alt="DIDay" ->}} - - - -### Was? - -Am Sonntag, dem 5. Juli, öffnet der Chaos Computer Club Berlin e.V. wieder seine Türen zum DID. - -Zusammen mit dem [xHain hack+makespace](https://x-hain.de/) unterstützen wir auf dem Weg in die digitale Unabhängigkeit. - -Gemeinsam arbeiten wir daran, unsere digitale Souveränität zurückzugewinnen. -Statt Abhängigkeiten von großen Plattformen setzen wir auf offene Alternativen und selbstbestimmte digitale Werkzeuge. -So holen wir uns Schritt für Schritt die Kontrolle über unser digitales Leben zurück und beschreiten den Weg zur digitalen Unabhängigkeit. - -Ob du jetzt - -- von WhatsApp zu einer datenschutzfreundlichen Alternative wechseln möchtest, -- dein Smartphone gerne ohne Google oder Apple betreiben willst, -- oder auf deinem Notebook lieber Linux anstelle von Windows benutzen würdest, - -wir helfen euch dabei gerne. Bringt gerne auch eure Geräte dafür mit. - -Natürlich kannst du auch einfach nur so vorbeikommen und uns Fragen stellen. - -### Wo? - -**Marienstraße 11, 10117 Berlin** - -### Wann? - -**Sonntag, 5. Juli 2026** \ -**12:00 bis 16:00 Uhr** - -Schaut aber auch gerne bei der -[Veranstaltung](tbd) -von [Digital-Zebra](https://termine.di.day/organisation/digitalzebra) und -der [c-base](https://termine.di.day/organisation/cbase) vorbei. - -**Gemeinsam mehr erreichen** \ -Diese Veranstaltung ist Teil eines Netzwerks aus mehreren Organisationen und Initiativen in Berlin. -Wir unterstützen uns gegenseitig mit Kompetenz, Erfahrung und praktischer Hilfe. -Uns alle eint der Wunsch, Wissen zu teilen, voneinander zu lernen und solidarisch zusammenzuarbeiten. -Der DI.Day bildet dabei den gemeinsamen Rahmen, -in dem wir uns für digitale Selbstbestimmung und nachhaltige digitale Strukturen einsetzen. - -Schau deshalb gern auch bei den Veranstaltungen der anderen beteiligten Organisationen vorbei. -So entsteht ein vielfältiges Angebot, das Austausch, Vernetzung und gegenseitige Unterstützung lebendig macht. diff --git a/content/veranstaltungen/didit.md b/content/veranstaltungen/didit.md index b5badfc..4e29790 100644 --- a/content/veranstaltungen/didit.md +++ b/content/veranstaltungen/didit.md @@ -11,10 +11,12 @@ menu: tag: ["Veranstaltung"] --- -**Jeden ersten Sonntag im Monat von 12:23 bis 17:42 Uhr** findet der Berliner Digital Independence Day statt. Der Veranstaltungsort wechselt monatlich zwischen den Räumen des CCCB (in den ungeraden Monaten Januar, März, Mai, …) und dem [xHain](https://x-hain.de/) (in den geraden Monaten). +In Berlin wird der [Digital Independence Day](https://diday.org) an verschiedenen Orten von einer breiten Zahl von Initiativen getragen. -Der CCCB und das xHain beteiligen sich gemeinsam an der internationalen [Digital Independence Day](https://diday.org)-Initiative. Diese Graswurzelbewegung ruft dazu auf, zu demokratiefreundlichen digitalen Alternativen zu wechseln, um die Abhängigkeit von großen Technologiekonzernen zu verringern. +Der CCCB beteiligt sich an dieser Graswurzelbewegung und ruft dazu auf, zu demokratiefreundlichen digitalen Alternativen zu wechseln, um die Abhängigkeit von großen Technologiekonzernen zu verringern. -Vor Ort gibt es praktische Hilfe beim Wechsel zu datenschutzfreundlichen Diensten, beim Einrichten von Linux oder beim Betrieb von Smartphones ohne große Tech-Konzerne. Egal ob Anfänger:in oder Fortgeschrittene:r. Kommt vorbei und bringt eure Geräte und Fragen mit. +Am ersten Sonntag im Monat gibt es praktische Hilfe beim Wechsel zu datenschutzfreundlichen Diensten, beim Einrichten von Linux oder beim Betrieb von Smartphones ohne große Tech-Konzerne. Egal, ob Anfänger:in oder Fortgeschrittene:r. Kommt vorbei und bringt eure Geräte und Fragen mit. -Weitere Informationen gibt es im [Ankündigungsbeitrag](https://berlin.ccc.de/post/2026/07/05/berlin-%23didit/). +Die Aktiven im CCCB unterstützen dabei auf verschiedenen Veranstaltungen in Berlin. + +Weitere Informationen zu konkreten Veranstaltungen gibt es im Terminkalender unter [https://events.diday.org/](https://events.diday.org/) bzw [https://events.diday.org/organisation/cccb][https://events.diday.org/organisation/cccb]. From 64ff74e5d276bc35afa94312c901256834d36907 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 4 Jul 2026 23:35:50 +0200 Subject: [PATCH 14/38] =?UTF-8?q?Behebe=20Termin=C3=BCbersicht=20bei=20Wie?= =?UTF-8?q?derholungen=20mit=20UNTIL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gen_upcoming.py normalisiert dtstart auf naive lokale Zeit, reichte die laut RFC 5545 in UTC anzugebende UNTIL-Zeit der RRULE aber tz-aware an dateutil weiter. Die Mischung aus naivem dtstart und tz-awarer UNTIL lässt dateutil.rrule mit "RRULE UNTIL values must be specified in UTC when DTSTART is timezone-aware" abbrechen -- der Build schlägt fehl, sobald ein wiederkehrender Termin ein UNTIL enthält. Mit ignoretz=True wird die UNTIL-Zeit ebenfalls naiv behandelt, konsistent zur restlichen Verarbeitung. Für Termine ohne UNTIL ist das ein No-Op. Fixes: 2e3a02af0cf4 ("refacture all the things!") Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Hauke Mehrtens --- tools/gen_upcoming.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/gen_upcoming.py b/tools/gen_upcoming.py index 33b093d..31763f7 100755 --- a/tools/gen_upcoming.py +++ b/tools/gen_upcoming.py @@ -44,7 +44,10 @@ def parse_recurring_event(event, start, end): logging.info(f"Processing recurring event {event['SUMMARY'].to_ical().decode('utf-8')}") dtstart = parse(event["DTSTART"].to_ical()) rs = rruleset() - rs.rrule(rrulestr(event["RRULE"].to_ical().decode("utf-8"), dtstart=dtstart)) + # dtstart is normalized to naive local time above; pass ignoretz so a + # tz-aware UNTIL (RFC 5545 requires UTC for it) is treated as naive too, + # otherwise dateutil rejects the naive/aware mismatch. + rs.rrule(rrulestr(event["RRULE"].to_ical().decode("utf-8"), dtstart=dtstart, ignoretz=True)) if "EXDATE" in event.keys(): for exdate in event["EXDATE"]: rs.exdate(parse(exdate.to_ical())) From 1130d7eef0588549a5594aff63b4b9bf6cbed564 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 4 Jul 2026 23:35:50 +0200 Subject: [PATCH 15/38] Beende die Di.Day-Reihe nach dem 3. Mai 2026 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der Digital Independence Day findet ab Juli 2026 nicht mehr im zweimonatlichen Turnus statt. Mit UNTIL in der RRULE endet die Wiederholung nach dem letzten Termin am 3. Mai 2026, sodass keine künftigen Instanzen mehr in den Kalendern (all.ics, veranstaltungen/index.ics) und in der Terminübersicht erscheinen. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Hauke Mehrtens --- content/veranstaltungen/didit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/veranstaltungen/didit.md b/content/veranstaltungen/didit.md index b5badfc..b89b44a 100644 --- a/content/veranstaltungen/didit.md +++ b/content/veranstaltungen/didit.md @@ -4,7 +4,7 @@ subtitle: "Digital Independence Day im CCCB" date: 2026-01-04T12:23:00+01:00 dtstart: 20260104T122300 dtend: 20260104T174200 -rrule: "FREQ=MONTHLY;INTERVAL=2;BYDAY=1SU;WKST=MO" +rrule: "FREQ=MONTHLY;INTERVAL=2;BYDAY=1SU;WKST=MO;UNTIL=20260503T235959Z" menu: main: parent: "Veranstaltungen" From 0318a0496aa82d4919fa945e92c5f010878fe9e6 Mon Sep 17 00:00:00 2001 From: Bruno Ranieri Date: Sat, 4 Jul 2026 23:37:19 +0200 Subject: [PATCH 16/38] fix typo --- content/veranstaltungen/didit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/veranstaltungen/didit.md b/content/veranstaltungen/didit.md index 4e29790..58c3267 100644 --- a/content/veranstaltungen/didit.md +++ b/content/veranstaltungen/didit.md @@ -19,4 +19,4 @@ Am ersten Sonntag im Monat gibt es praktische Hilfe beim Wechsel zu datenschutzf Die Aktiven im CCCB unterstützen dabei auf verschiedenen Veranstaltungen in Berlin. -Weitere Informationen zu konkreten Veranstaltungen gibt es im Terminkalender unter [https://events.diday.org/](https://events.diday.org/) bzw [https://events.diday.org/organisation/cccb][https://events.diday.org/organisation/cccb]. +Weitere Informationen zu konkreten Veranstaltungen gibt es im Terminkalender unter [https://events.diday.org/](https://events.diday.org/) bzw [https://events.diday.org/organisation/cccb](https://events.diday.org/organisation/cccb). From d8773f4f6fdc68a8b6e403a91a3e32ff48dea29b Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 4 Jul 2026 23:41:25 +0200 Subject: [PATCH 17/38] Weise auf Ausfall des DI.Day am 5. Juli im CCCB hin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der DI.Day findet am 5. Juli 2026 nicht im Chaos Computer Club Berlin statt. Der neue Blog-Eintrag informiert darüber und verweist auf die alternativen Berliner DI.Day-Veranstaltungen (c-base, Stadtschloss Moabit). Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Hauke Mehrtens --- .../post/2026-07-04-kein-diday-im-cccb/index.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 content/post/2026-07-04-kein-diday-im-cccb/index.md diff --git a/content/post/2026-07-04-kein-diday-im-cccb/index.md b/content/post/2026-07-04-kein-diday-im-cccb/index.md new file mode 100644 index 0000000..d64dd4b --- /dev/null +++ b/content/post/2026-07-04-kein-diday-im-cccb/index.md @@ -0,0 +1,15 @@ +--- +title: "Kein DI.Day am 5. Juli im CCCB" +date: 2026-07-04T12:00:00+02:00 +showHero: false +tags: ["di.day", "Ankündigung"] +--- + +**Kurzfristige Änderung:** Der [Digital Independence Day](/veranstaltungen/didit/) findet am **Sonntag, dem 5. Juli 2026, nicht** im Chaos Computer Club Berlin (Marienstraße 11) statt. + +Wer trotzdem am DI.Day teilnehmen und den Weg in die digitale Unabhängigkeit weitergehen möchte, ist herzlich bei den anderen Berliner Veranstaltungen willkommen: + +- [„Let's DID it!" mit Linux & Sommerfest der BELUG](https://f.termine.di.day/events/ee48fdda-a134-4f27-932e-b87c7a9fa24a) in der c-base +- [DI.Day im Stadtschloss Moabit](https://f.termine.di.day/events/41ab17fe-05ab-4308-9abb-d38d9485fd4f) + +Weitere Termine und Orte findet ihr wie immer auf [termine.di.day](https://termine.di.day/). From 43ae6bc869f1d2fd33b5e85d0dafd1fcd90b59d0 Mon Sep 17 00:00:00 2001 From: xengi Date: Wed, 22 Jul 2026 22:11:21 +0200 Subject: [PATCH 18/38] Update .forgejo/workflows/deploy.yaml --- .forgejo/workflows/deploy.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index b0b9a6c..ba383ac 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -21,10 +21,16 @@ jobs: git version hugo version python --version + + - name: Set envionment vars + run: | + echo "GIT_BRANCH=${{ forgejo.event_name == 'schedule' && 'production' || forgejo.ref_name }}" >> "$FORGEJO_ENV" + echo "SSH_PRIVATE_KEY=${{ env.GIT_BRANCH == 'production' && secrets.SSH_PRIVATE_KEY_PRODUCTION || secrets.SSH_PRIVATE_KEY_STAGING }}" >> "$FORGEJO_ENV" + echo "DEPLOY_DIR=${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }}" >> "$FORGEJO_ENV" - name: Checkout repository run: | - git clone -b ${{ forgejo.ref_name }} --recursive https://git.berlin.ccc.de/cccb-website-team/www.git . + git clone -b $GIT_BRANCH --recursive https://git.berlin.ccc.de/cccb-website-team/www.git . git status - name: Install Python depenndencies @@ -34,8 +40,6 @@ jobs: run: ./build.sh - name: Setup SSH - env: - SSH_PRIVATE_KEY: ${{ forgejo.ref_name == 'production' && secrets.SSH_PRIVATE_KEY_PRODUCTION || secrets.SSH_PRIVATE_KEY_STAGING }} run: | mkdir -p ~/.ssh printf "%s" "${{ secrets.KNOWN_HOSTS }}" | base64 -d > ~/.ssh/known_hosts @@ -45,8 +49,6 @@ jobs: cat ~/.ssh/id_ed25519.pub - name: Rsync rendered site - env: - DEPLOY_DIR: ${{ forgejo.ref_name == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} # TODO: add --delete run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:$DEPLOY_DIR From 8b4f6d3c95204fd16ba817470b804047d80116d2 Mon Sep 17 00:00:00 2001 From: April John Date: Tue, 11 Aug 2026 21:16:19 +0200 Subject: [PATCH 19/38] =?UTF-8?q?Aktionstag=20gegen=20=C3=9Cberwachung=202?= =?UTF-8?q?026-08-23:=20Veranstaltung=20+=20Ank=C3=BCndigungspost?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- .../index.md | 60 +++++++++++++++++++ .../aktionstag-ueberwachung.md | 23 +++++++ 2 files changed, 83 insertions(+) create mode 100644 content/post/2026-08-23-aktionstag-ueberwachung/index.md create mode 100644 content/veranstaltungen/aktionstag-ueberwachung.md diff --git a/content/post/2026-08-23-aktionstag-ueberwachung/index.md b/content/post/2026-08-23-aktionstag-ueberwachung/index.md new file mode 100644 index 0000000..206f048 --- /dev/null +++ b/content/post/2026-08-23-aktionstag-ueberwachung/index.md @@ -0,0 +1,60 @@ +--- +title: "Aktionstag gegen Überwachung" +date: 2026-08-11T12:00:00+02:00 +showHero: false +tags: ["Überwachung", "Ankündigung"] +--- + +### Was? + +KI-gestützte Überwachungskameras sollen jetzt auch nach Berlin kommen. +Mit der im Dezember 2025 beschlossenen [Verschärfung des Berliner Polizeigesetzes (ASOG)](https://www.beck-aktuell.de/heute-im-recht/rechtspolitik-gesetzgebung/berlin-verschaerfung-polizeigesetz-2025-12-04) darf die Polizei solche Kameras an öffentlichen Plätzen anbringen – und erste Versuche laufen bereits. + +Wir finden: Darüber muss geredet werden. +Deshalb lädt der Chaos Computer Club Berlin zum Aktionstag gegen Überwachung. + +### Worum geht es? + +An sechs sogenannten „kriminalitätsbelasteten Orten" – darunter der Alexanderplatz, das Rote Rathaus und das Alte Stadthaus – soll [in einem einjährigen Probelauf KI-Videoüberwachung getestet werden, dazu kommt mobile Technik vor dem Abgeordnetenhaus](https://taz.de/KI-Videoueberwachung-in-Berlin/!6160851/). +Die Systeme beschränken sich nicht aufs Aufzeichnen: Sogenannte Verhaltensscanner sollen automatisch erkennen, wenn sich jemand „auffällig" verhält – [trainiert unter anderem mit den Daten von Passant:innen, die einfach nur vorbeilaufen](https://netzpolitik.org/2026/ki-gestuetzte-videoueberwachung-in-berlin-so-wehrt-man-sich-gegen-verhaltensscanner/). + +Was dabei herauskommt, lässt sich anderswo besichtigen: In Mannheim läuft ein solches System seit 2018, in Hamburg seit 2023. +Die Software verwechselt dabei schon mal [eine Umarmung mit einem Ringkampf](https://taz.de/Kuenstliche-Intelligenz-im-Einsatz/!6099559/), und die Fehlalarmquote lag in Mannheim laut Polizei [im „niedrigen zweistelligen Bereich" – pro Tag](https://netzpolitik.org/2023/intelligente-videoueberwachung-polizei-hamburg-will-ab-juli-verhalten-automatisch-scannen/). +Wer sich hinlegt oder taumelt, wird zum Alarmfall. +Was als „auffällig" gilt, entscheidet der Algorithmus – mit allem [Diskriminierungspotenzial, das dazugehört](https://verfassungsblog.de/berlin-asog-novelle-kbos/). + +Die Kameras sind dabei nur ein Baustein: Dieselbe Gesetzesnovelle weitet auch [Datenspeicherung und weitere Überwachungsbefugnisse deutlich aus](https://www.telepolis.de/article/Berliner-Polizeigesetz-Koalition-weitet-Ueberwachung-aus-11083345.html) – Kritik kam unter anderem von der Berliner Datenschutzbeauftragten. +Der CCC hat die Pläne bereits im Innenausschuss des Abgeordnetenhauses kritisiert. + +Alle Interessierten sind herzlich willkommen, Vorwissen ist nicht nötig. + +### Programm + +**13:00 Uhr – Open Space** \ +Wir starten den Tag mit einem offenen Austausch: Bringt eure Fragen, Bedenken und Ideen mit – ob ihr euch schon lange mit Überwachung beschäftigt oder gerade erst davon gehört habt. + +**15:00 Uhr – Vortrag** \ +Ein Vortrag zu KI-Überwachungskameras, Verhaltenstracking und dem neuen Berliner Polizeigesetz: Was ist geplant, was können die Systeme (nicht), und was bedeutet das für uns alle? + +**16:00 Uhr – Podiumsdiskussion** \ +Im Anschluss diskutieren wir auf dem Podium über die KI-Videoüberwachung in Berlin und wie sich die Zivilgesellschaft dagegen wehren kann – mit Raum für eure Fragen. + +### Wo? + +📍 **Chaos Computer Club Berlin, Marienstraße 11, 10117 Berlin** + +🚈 Etwa 5 Minuten ab dem S-Bahnhof Friedrichstraße + +### Wann? + +**📆 Sonntag, 23. August 2026** \ +**ab 13:00 Uhr** + +### Zum Weiterlesen + +- taz: [KI-Videoüberwachung in Berlin: Verhaltensscanner bald auch vor dem Abgeordnetenhaus](https://taz.de/KI-Videoueberwachung-in-Berlin/!6160851/) +- netzpolitik.org: [So wehrt man sich gegen Verhaltensscanner](https://netzpolitik.org/2026/ki-gestuetzte-videoueberwachung-in-berlin-so-wehrt-man-sich-gegen-verhaltensscanner/) – mit Tools und Material für die Zivilgesellschaft +- Verfassungsblog: [„Try harder hilft selten" – zur verfassungsrechtlichen Einordnung der ASOG-Novelle](https://verfassungsblog.de/berlin-asog-novelle-kbos/) +- taz: [Reform des Berliner Polizeigesetzes: Riskantes Manöver](https://taz.de/Reform-des-Berliner-Polizeigesetzes/!6096087/) +- Telepolis: [Berliner Polizeigesetz: Koalition weitet Überwachung aus](https://www.telepolis.de/article/Berliner-Polizeigesetz-Koalition-weitet-Ueberwachung-aus-11083345.html) +- beck-aktuell: [Kameras und KI-Einsatz: Berlin verschärft Polizeigesetz](https://www.beck-aktuell.de/heute-im-recht/rechtspolitik-gesetzgebung/berlin-verschaerfung-polizeigesetz-2025-12-04) diff --git a/content/veranstaltungen/aktionstag-ueberwachung.md b/content/veranstaltungen/aktionstag-ueberwachung.md new file mode 100644 index 0000000..802c72c --- /dev/null +++ b/content/veranstaltungen/aktionstag-ueberwachung.md @@ -0,0 +1,23 @@ +--- +title: "Aktionstag gegen Überwachung" +subtitle: "KI-Überwachungskameras in Berlin – Vorträge und Austausch" +date: 2026-08-11T12:00:00+02:00 +dtstart: 20260823T130000 +dtend: 20260823T180000 +menu: + main: + parent: "Veranstaltungen" +tag: ["Veranstaltung"] +--- + +**Am 23. August lädt der Chaos Computer Club Berlin zum Aktionstag gegen Überwachung.** + +KI-gestützte Überwachungskameras sollen jetzt auch nach Berlin kommen: Das neue Berliner Polizeigesetz erlaubt ihre Anbringung an öffentlichen Plätzen, erste Versuche – inklusive Verhaltenstracking – laufen bereits. + +Das Programm: + +- **13:00 Uhr** – Open Space: Gespräche und Austausch untereinander +- **15:00 Uhr** – Vortrag zu KI-Überwachungskameras, Verhaltenstracking und dem neuen Berliner Polizeigesetz +- **16:00 Uhr** – Podiumsdiskussion + +📍 Chaos Computer Club Berlin, Marienstraße 11, 10117 Berlin From 9b8fbc0106d7b2a9127a69a7d041b2f93151664a Mon Sep 17 00:00:00 2001 From: April John Date: Tue, 11 Aug 2026 21:34:13 +0200 Subject: [PATCH 20/38] =?UTF-8?q?Text=20nat=C3=BCrlicher=20formuliert,=20G?= =?UTF-8?q?edankenstriche=20entfernt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- .../index.md | 37 +++++++++---------- .../aktionstag-ueberwachung.md | 10 ++--- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/content/post/2026-08-23-aktionstag-ueberwachung/index.md b/content/post/2026-08-23-aktionstag-ueberwachung/index.md index 206f048..34b1320 100644 --- a/content/post/2026-08-23-aktionstag-ueberwachung/index.md +++ b/content/post/2026-08-23-aktionstag-ueberwachung/index.md @@ -8,36 +8,33 @@ tags: ["Überwachung", "Ankündigung"] ### Was? KI-gestützte Überwachungskameras sollen jetzt auch nach Berlin kommen. -Mit der im Dezember 2025 beschlossenen [Verschärfung des Berliner Polizeigesetzes (ASOG)](https://www.beck-aktuell.de/heute-im-recht/rechtspolitik-gesetzgebung/berlin-verschaerfung-polizeigesetz-2025-12-04) darf die Polizei solche Kameras an öffentlichen Plätzen anbringen – und erste Versuche laufen bereits. +Das [im Dezember 2025 verschärfte Berliner Polizeigesetz](https://www.beck-aktuell.de/heute-im-recht/rechtspolitik-gesetzgebung/berlin-verschaerfung-polizeigesetz-2025-12-04) erlaubt der Polizei, solche Kameras an öffentlichen Plätzen aufzuhängen. Erste Versuche laufen schon. -Wir finden: Darüber muss geredet werden. -Deshalb lädt der Chaos Computer Club Berlin zum Aktionstag gegen Überwachung. +Darüber wollen wir reden. +Deshalb laden wir am 23. August zum Aktionstag gegen Überwachung in den Club ein. ### Worum geht es? -An sechs sogenannten „kriminalitätsbelasteten Orten" – darunter der Alexanderplatz, das Rote Rathaus und das Alte Stadthaus – soll [in einem einjährigen Probelauf KI-Videoüberwachung getestet werden, dazu kommt mobile Technik vor dem Abgeordnetenhaus](https://taz.de/KI-Videoueberwachung-in-Berlin/!6160851/). -Die Systeme beschränken sich nicht aufs Aufzeichnen: Sogenannte Verhaltensscanner sollen automatisch erkennen, wenn sich jemand „auffällig" verhält – [trainiert unter anderem mit den Daten von Passant:innen, die einfach nur vorbeilaufen](https://netzpolitik.org/2026/ki-gestuetzte-videoueberwachung-in-berlin-so-wehrt-man-sich-gegen-verhaltensscanner/). +Die KI-Videoüberwachung soll [ein Jahr lang an sechs sogenannten „kriminalitätsbelasteten Orten" getestet werden](https://taz.de/KI-Videoueberwachung-in-Berlin/!6160851/), darunter am Alexanderplatz, am Roten Rathaus und am Alten Stadthaus. Vor dem Abgeordnetenhaus kommt mobile Technik dazu. -Was dabei herauskommt, lässt sich anderswo besichtigen: In Mannheim läuft ein solches System seit 2018, in Hamburg seit 2023. -Die Software verwechselt dabei schon mal [eine Umarmung mit einem Ringkampf](https://taz.de/Kuenstliche-Intelligenz-im-Einsatz/!6099559/), und die Fehlalarmquote lag in Mannheim laut Polizei [im „niedrigen zweistelligen Bereich" – pro Tag](https://netzpolitik.org/2023/intelligente-videoueberwachung-polizei-hamburg-will-ab-juli-verhalten-automatisch-scannen/). -Wer sich hinlegt oder taumelt, wird zum Alarmfall. -Was als „auffällig" gilt, entscheidet der Algorithmus – mit allem [Diskriminierungspotenzial, das dazugehört](https://verfassungsblog.de/berlin-asog-novelle-kbos/). +Diese Kameras zeichnen nicht nur auf. Sogenannte Verhaltensscanner sollen automatisch melden, wenn sich jemand „auffällig" verhält. Trainiert wird das Ganze [mit den Daten von Passant:innen, die einfach nur vorbeilaufen](https://netzpolitik.org/2026/ki-gestuetzte-videoueberwachung-in-berlin-so-wehrt-man-sich-gegen-verhaltensscanner/). -Die Kameras sind dabei nur ein Baustein: Dieselbe Gesetzesnovelle weitet auch [Datenspeicherung und weitere Überwachungsbefugnisse deutlich aus](https://www.telepolis.de/article/Berliner-Polizeigesetz-Koalition-weitet-Ueberwachung-aus-11083345.html) – Kritik kam unter anderem von der Berliner Datenschutzbeauftragten. -Der CCC hat die Pläne bereits im Innenausschuss des Abgeordnetenhauses kritisiert. +In Mannheim läuft so ein System seit 2018, in Hamburg seit 2023. Dort hält die Software [eine Umarmung schon mal für einen Ringkampf](https://taz.de/Kuenstliche-Intelligenz-im-Einsatz/!6099559/). In Mannheim gab es laut Polizei [jeden Tag Fehlalarme im „niedrigen zweistelligen Bereich"](https://netzpolitik.org/2023/intelligente-videoueberwachung-polizei-hamburg-will-ab-juli-verhalten-automatisch-scannen/). Wer sich hinlegt oder taumelt, löst Alarm aus. Was überhaupt als „auffällig" gilt, entscheidet der Algorithmus. Warum das [Menschen diskriminieren kann, erklärt der Verfassungsblog](https://verfassungsblog.de/berlin-asog-novelle-kbos/). -Alle Interessierten sind herzlich willkommen, Vorwissen ist nicht nötig. +Die Kameras sind außerdem nur ein Teil der Gesetzesänderung. Das neue ASOG erlaubt auch [längere Datenspeicherung und weitere Überwachungsbefugnisse](https://www.telepolis.de/article/Berliner-Polizeigesetz-Koalition-weitet-Ueberwachung-aus-11083345.html). Die Berliner Datenschutzbeauftragte hat das kritisiert. Wir auch: Der CCC war dazu bereits im Innenausschuss des Abgeordnetenhauses. + +Ihr braucht kein Vorwissen. Kommt einfach vorbei. ### Programm -**13:00 Uhr – Open Space** \ -Wir starten den Tag mit einem offenen Austausch: Bringt eure Fragen, Bedenken und Ideen mit – ob ihr euch schon lange mit Überwachung beschäftigt oder gerade erst davon gehört habt. +**13:00 Uhr: Open Space** \ +Wir fangen mit offenem Austausch an. Bringt eure Fragen mit, egal ob ihr euch schon lange mit dem Thema beschäftigt oder gerade zum ersten Mal davon hört. -**15:00 Uhr – Vortrag** \ -Ein Vortrag zu KI-Überwachungskameras, Verhaltenstracking und dem neuen Berliner Polizeigesetz: Was ist geplant, was können die Systeme (nicht), und was bedeutet das für uns alle? +**15:00 Uhr: Vortrag** \ +Was in Berlin geplant ist, was die Technik wirklich kann und was das für uns alle heißt. -**16:00 Uhr – Podiumsdiskussion** \ -Im Anschluss diskutieren wir auf dem Podium über die KI-Videoüberwachung in Berlin und wie sich die Zivilgesellschaft dagegen wehren kann – mit Raum für eure Fragen. +**16:00 Uhr: Podiumsdiskussion** \ +Danach diskutieren wir auf dem Podium, wie wir uns gegen die KI-Videoüberwachung wehren können. Fragen aus dem Publikum sind ausdrücklich erwünscht. ### Wo? @@ -53,8 +50,8 @@ Im Anschluss diskutieren wir auf dem Podium über die KI-Videoüberwachung in Be ### Zum Weiterlesen - taz: [KI-Videoüberwachung in Berlin: Verhaltensscanner bald auch vor dem Abgeordnetenhaus](https://taz.de/KI-Videoueberwachung-in-Berlin/!6160851/) -- netzpolitik.org: [So wehrt man sich gegen Verhaltensscanner](https://netzpolitik.org/2026/ki-gestuetzte-videoueberwachung-in-berlin-so-wehrt-man-sich-gegen-verhaltensscanner/) – mit Tools und Material für die Zivilgesellschaft -- Verfassungsblog: [„Try harder hilft selten" – zur verfassungsrechtlichen Einordnung der ASOG-Novelle](https://verfassungsblog.de/berlin-asog-novelle-kbos/) +- netzpolitik.org: [So wehrt man sich gegen Verhaltensscanner](https://netzpolitik.org/2026/ki-gestuetzte-videoueberwachung-in-berlin-so-wehrt-man-sich-gegen-verhaltensscanner/) (mit Tools und Material für die Zivilgesellschaft) +- Verfassungsblog: [„Try harder hilft selten": die ASOG-Novelle verfassungsrechtlich eingeordnet](https://verfassungsblog.de/berlin-asog-novelle-kbos/) - taz: [Reform des Berliner Polizeigesetzes: Riskantes Manöver](https://taz.de/Reform-des-Berliner-Polizeigesetzes/!6096087/) - Telepolis: [Berliner Polizeigesetz: Koalition weitet Überwachung aus](https://www.telepolis.de/article/Berliner-Polizeigesetz-Koalition-weitet-Ueberwachung-aus-11083345.html) - beck-aktuell: [Kameras und KI-Einsatz: Berlin verschärft Polizeigesetz](https://www.beck-aktuell.de/heute-im-recht/rechtspolitik-gesetzgebung/berlin-verschaerfung-polizeigesetz-2025-12-04) diff --git a/content/veranstaltungen/aktionstag-ueberwachung.md b/content/veranstaltungen/aktionstag-ueberwachung.md index 802c72c..6976864 100644 --- a/content/veranstaltungen/aktionstag-ueberwachung.md +++ b/content/veranstaltungen/aktionstag-ueberwachung.md @@ -1,6 +1,6 @@ --- title: "Aktionstag gegen Überwachung" -subtitle: "KI-Überwachungskameras in Berlin – Vorträge und Austausch" +subtitle: "KI-Überwachungskameras in Berlin: Vortrag, Podium und Austausch" date: 2026-08-11T12:00:00+02:00 dtstart: 20260823T130000 dtend: 20260823T180000 @@ -12,12 +12,12 @@ tag: ["Veranstaltung"] **Am 23. August lädt der Chaos Computer Club Berlin zum Aktionstag gegen Überwachung.** -KI-gestützte Überwachungskameras sollen jetzt auch nach Berlin kommen: Das neue Berliner Polizeigesetz erlaubt ihre Anbringung an öffentlichen Plätzen, erste Versuche – inklusive Verhaltenstracking – laufen bereits. +KI-gestützte Überwachungskameras sollen jetzt auch nach Berlin kommen. Das neue Berliner Polizeigesetz erlaubt es, sie an öffentlichen Plätzen aufzuhängen. Erste Versuche laufen schon, Verhaltenstracking inklusive. Darüber wollen wir reden. Das Programm: -- **13:00 Uhr** – Open Space: Gespräche und Austausch untereinander -- **15:00 Uhr** – Vortrag zu KI-Überwachungskameras, Verhaltenstracking und dem neuen Berliner Polizeigesetz -- **16:00 Uhr** – Podiumsdiskussion +- **13:00 Uhr:** Open Space, offener Austausch untereinander +- **15:00 Uhr:** Vortrag zu den KI-Kameras und dem neuen Berliner Polizeigesetz +- **16:00 Uhr:** Podiumsdiskussion 📍 Chaos Computer Club Berlin, Marienstraße 11, 10117 Berlin From 5f603574e3e3b28718f6dd261758dc6eca9374d0 Mon Sep 17 00:00:00 2001 From: aprl Date: Tue, 11 Aug 2026 21:41:01 +0200 Subject: [PATCH 21/38] :nerd: minor spelling mistake :sparkle: Signed-off-by: aprl --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index ba383ac..adae1c6 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -33,7 +33,7 @@ jobs: git clone -b $GIT_BRANCH --recursive https://git.berlin.ccc.de/cccb-website-team/www.git . git status - - name: Install Python depenndencies + - name: Install Python dependencies run: python -m pip install -r requirements.txt --break-system-packages - name: Render site From c18cce53f8f621670e4bbf0af5ed198122972acd Mon Sep 17 00:00:00 2001 From: aprl Date: Tue, 11 Aug 2026 22:05:13 +0200 Subject: [PATCH 22/38] Update .forgejo/workflows/deploy.yaml --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index adae1c6..1da9991 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -50,7 +50,7 @@ jobs: - name: Rsync rendered site # TODO: add --delete - run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:$DEPLOY_DIR + run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:/srv/http/www - name: Cleanup if: ${{ always() }} From d3fd2ec8a782bd98cecea61c5061580fbba2e33d Mon Sep 17 00:00:00 2001 From: aprl Date: Tue, 11 Aug 2026 22:05:43 +0200 Subject: [PATCH 23/38] Update .forgejo/workflows/deploy.yaml --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index 1da9991..adae1c6 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -50,7 +50,7 @@ jobs: - name: Rsync rendered site # TODO: add --delete - run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:/srv/http/www + run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:$DEPLOY_DIR - name: Cleanup if: ${{ always() }} From c2a2f6e160ee66cb0c0df7b82150b478e4f6ccb5 Mon Sep 17 00:00:00 2001 From: aprl Date: Tue, 11 Aug 2026 22:07:01 +0200 Subject: [PATCH 24/38] Update .forgejo/workflows/deploy.yaml --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index adae1c6..1da9991 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -50,7 +50,7 @@ jobs: - name: Rsync rendered site # TODO: add --delete - run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:$DEPLOY_DIR + run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:/srv/http/www - name: Cleanup if: ${{ always() }} From dfae28d575654c5452bc3618a5673aeec757f6e7 Mon Sep 17 00:00:00 2001 From: aprl Date: Tue, 11 Aug 2026 22:10:47 +0200 Subject: [PATCH 25/38] Update .forgejo/workflows/deploy.yaml --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index 1da9991..adae1c6 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -50,7 +50,7 @@ jobs: - name: Rsync rendered site # TODO: add --delete - run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:/srv/http/www + run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:$DEPLOY_DIR - name: Cleanup if: ${{ always() }} From 96919a71888bf9a6d7d94f6e44c123be7934af0a Mon Sep 17 00:00:00 2001 From: "Ricardo (XenGi) Band" Date: Tue, 11 Aug 2026 22:20:30 +0200 Subject: [PATCH 26/38] fix pipeline --- .forgejo/workflows/deploy.yaml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index adae1c6..d86974b 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -1,4 +1,5 @@ name: deploy blog + on: workflow_dispatch: schedule: @@ -11,7 +12,7 @@ on: jobs: deploy: runs-on: ubuntu-latest - steps: + steps: - name: Install dependencies run: apk --no-cache add hugo python3 py3-pip git openssh-client rsync @@ -23,11 +24,8 @@ jobs: python --version - name: Set envionment vars - run: | - echo "GIT_BRANCH=${{ forgejo.event_name == 'schedule' && 'production' || forgejo.ref_name }}" >> "$FORGEJO_ENV" - echo "SSH_PRIVATE_KEY=${{ env.GIT_BRANCH == 'production' && secrets.SSH_PRIVATE_KEY_PRODUCTION || secrets.SSH_PRIVATE_KEY_STAGING }}" >> "$FORGEJO_ENV" - echo "DEPLOY_DIR=${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }}" >> "$FORGEJO_ENV" - + run: echo "GIT_BRANCH=${{ forgejo.event_name == 'schedule' && 'production' || forgejo.ref_name }}" >> "$FORGEJO_ENV" + - name: Checkout repository run: | git clone -b $GIT_BRANCH --recursive https://git.berlin.ccc.de/cccb-website-team/www.git . @@ -43,15 +41,15 @@ jobs: run: | mkdir -p ~/.ssh printf "%s" "${{ secrets.KNOWN_HOSTS }}" | base64 -d > ~/.ssh/known_hosts - printf "%s" "$SSH_PRIVATE_KEY" | base64 -d > ~/.ssh/id_ed25519 + printf "%s" "${{ env.GIT_BRANCH == 'production' && secrets.SSH_PRIVATE_KEY_PRODUCTION || secrets.SSH_PRIVATE_KEY_STAGING }}" | base64 -d > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh-keygen -f ~/.ssh/id_ed25519 -y > ~/.ssh/id_ed25519.pub cat ~/.ssh/id_ed25519.pub - name: Rsync rendered site - # TODO: add --delete - run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:$DEPLOY_DIR + run: rsync -var --delete -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} - name: Cleanup if: ${{ always() }} run: rm -rf ~/.ssh + From 2ba5b8cfa8a9318239737c775095a77628a840ef Mon Sep 17 00:00:00 2001 From: "Ricardo (XenGi) Band" Date: Tue, 11 Aug 2026 22:29:30 +0200 Subject: [PATCH 27/38] fix pipeline --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index d86974b..c745480 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -47,7 +47,7 @@ jobs: cat ~/.ssh/id_ed25519.pub - name: Rsync rendered site - run: rsync -var --delete -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} + run: rsync -var --delete-after -e 'ssh -vvv -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} - name: Cleanup if: ${{ always() }} From f839b1b01a9ce465fb607861f2331633ccf6184c Mon Sep 17 00:00:00 2001 From: xengi Date: Tue, 11 Aug 2026 22:37:45 +0200 Subject: [PATCH 28/38] Update .forgejo/workflows/deploy.yaml Signed-off-by: xengi --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index c745480..eb7676a 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -47,7 +47,7 @@ jobs: cat ~/.ssh/id_ed25519.pub - name: Rsync rendered site - run: rsync -var --delete-after -e 'ssh -vvv -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} + run: rsync -var --delete-after -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} - name: Cleanup if: ${{ always() }} From 87e123030158772c2377a0d27f536e0399ca1320 Mon Sep 17 00:00:00 2001 From: "Ricardo (XenGi) Band" Date: Tue, 11 Aug 2026 22:45:17 +0200 Subject: [PATCH 29/38] unfix pipeline --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index eb7676a..c745480 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -47,7 +47,7 @@ jobs: cat ~/.ssh/id_ed25519.pub - name: Rsync rendered site - run: rsync -var --delete-after -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} + run: rsync -var --delete-after -e 'ssh -vvv -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} - name: Cleanup if: ${{ always() }} From bac896e60fa8161177c6a2c99d6d476849c9b0a7 Mon Sep 17 00:00:00 2001 From: xengi Date: Tue, 11 Aug 2026 22:57:01 +0200 Subject: [PATCH 30/38] Update .forgejo/workflows/deploy.yaml --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index c745480..1c54057 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -47,7 +47,7 @@ jobs: cat ~/.ssh/id_ed25519.pub - name: Rsync rendered site - run: rsync -var --delete-after -e 'ssh -vvv -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} + run: rsync -var --delete -e 'ssh -vvv -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} - name: Cleanup if: ${{ always() }} From bafe2bcb816acabbdbdd3e47d54cc8578d73e1e0 Mon Sep 17 00:00:00 2001 From: xengi Date: Tue, 11 Aug 2026 23:05:26 +0200 Subject: [PATCH 31/38] Update .forgejo/workflows/deploy.yaml --- .forgejo/workflows/deploy.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index 1c54057..73cd71b 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -22,6 +22,8 @@ jobs: git version hugo version python --version + rsync --version + ssh -V - name: Set envionment vars run: echo "GIT_BRANCH=${{ forgejo.event_name == 'schedule' && 'production' || forgejo.ref_name }}" >> "$FORGEJO_ENV" From 7689abaf3e63b2a6977f9f69d565a533c650ff5b Mon Sep 17 00:00:00 2001 From: xengi Date: Tue, 11 Aug 2026 23:13:51 +0200 Subject: [PATCH 32/38] Update .forgejo/workflows/deploy.yaml --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index 73cd71b..dfd80bd 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -49,7 +49,7 @@ jobs: cat ~/.ssh/id_ed25519.pub - name: Rsync rendered site - run: rsync -var --delete -e 'ssh -vvv -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} + run: rsync -var --delete -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} - name: Cleanup if: ${{ always() }} From b1ff3727c8c054e31f88ae1c04eb621425c4d0bf Mon Sep 17 00:00:00 2001 From: xengi Date: Tue, 11 Aug 2026 23:21:32 +0200 Subject: [PATCH 33/38] Update .forgejo/workflows/deploy.yaml Signed-off-by: xengi --- .forgejo/workflows/deploy.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index dfd80bd..1813837 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -49,7 +49,8 @@ jobs: cat ~/.ssh/id_ed25519.pub - name: Rsync rendered site - run: rsync -var --delete -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} + # TODO: add --delete + run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} - name: Cleanup if: ${{ always() }} From 5368e752404e1eada42ede2188dd84bd9116da8c Mon Sep 17 00:00:00 2001 From: aprl Date: Tue, 11 Aug 2026 23:31:40 +0200 Subject: [PATCH 34/38] Add .forgejo/workflows/miau.yaml --- .forgejo/workflows/miau.yaml | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .forgejo/workflows/miau.yaml diff --git a/.forgejo/workflows/miau.yaml b/.forgejo/workflows/miau.yaml new file mode 100644 index 0000000..1813837 --- /dev/null +++ b/.forgejo/workflows/miau.yaml @@ -0,0 +1,58 @@ +name: deploy blog + +on: + workflow_dispatch: + schedule: + - cron: '0 10 * * *' # daily at 10:00 + push: + branches: + - staging + - production + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Install dependencies + run: apk --no-cache add hugo python3 py3-pip git openssh-client rsync + + - name: Check versions + run: | + cat /etc/os-release + git version + hugo version + python --version + rsync --version + ssh -V + + - name: Set envionment vars + run: echo "GIT_BRANCH=${{ forgejo.event_name == 'schedule' && 'production' || forgejo.ref_name }}" >> "$FORGEJO_ENV" + + - name: Checkout repository + run: | + git clone -b $GIT_BRANCH --recursive https://git.berlin.ccc.de/cccb-website-team/www.git . + git status + + - name: Install Python dependencies + run: python -m pip install -r requirements.txt --break-system-packages + + - name: Render site + run: ./build.sh + + - name: Setup SSH + run: | + mkdir -p ~/.ssh + printf "%s" "${{ secrets.KNOWN_HOSTS }}" | base64 -d > ~/.ssh/known_hosts + printf "%s" "${{ env.GIT_BRANCH == 'production' && secrets.SSH_PRIVATE_KEY_PRODUCTION || secrets.SSH_PRIVATE_KEY_STAGING }}" | base64 -d > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh-keygen -f ~/.ssh/id_ed25519 -y > ~/.ssh/id_ed25519.pub + cat ~/.ssh/id_ed25519.pub + + - name: Rsync rendered site + # TODO: add --delete + run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} + + - name: Cleanup + if: ${{ always() }} + run: rm -rf ~/.ssh + From c28f04c6e85cd0acac8b81294c9b430056ba3263 Mon Sep 17 00:00:00 2001 From: "Ricardo (XenGi) Band" Date: Wed, 12 Aug 2026 02:01:58 +0200 Subject: [PATCH 35/38] switch to ics files; make calendars work; fix some minor issues --- .editorconfig | 7 +- .gitattributes | 1 - .gitignore | 135 +++++++++++++++++--- .python-version | 1 - README.md | 28 ++-- assets/js/calendar.js | 94 +++++++------- assets/js/clubstatus.js | 6 +- build.sh | 7 +- config/_default/hugo.toml | 2 +- content/_index.md | 5 +- content/post/Neujahresempfang-2026/index.md | 1 + content/veranstaltungen/neujahresempfang.md | 2 +- content/verein/calendar/index.md | 13 +- flake.lock | 8 +- flake.nix | 13 +- requirements.txt | 2 - static/js/upcoming.js | 113 ++++++++++++++++ tools/gen_upcoming.py | 108 ---------------- tools/merge_cals.py | 31 ----- 19 files changed, 318 insertions(+), 259 deletions(-) delete mode 100644 .gitattributes delete mode 100644 .python-version delete mode 100644 requirements.txt create mode 100644 static/js/upcoming.js delete mode 100755 tools/gen_upcoming.py delete mode 100755 tools/merge_cals.py diff --git a/.editorconfig b/.editorconfig index 4e8e071..6e5b9f9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,11 +9,6 @@ charset = utf-8 end_of_line = lf insert_final_newline = true -[*.py] -indent_style = space -indent_size = 4 - -[*.yaml] +[*.{js,yaml}] indent_style = space indent_size = 2 - diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index ae018fa..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.ics text eol=crlf diff --git a/.gitignore b/.gitignore index 18286ce..008e122 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,9 @@ -static/all.ics +# Created by https://www.toptal.com/developers/gitignore/api/windows,linux,macos,hugo,pycharm+all,vim,direnv +# Edit at https://www.toptal.com/developers/gitignore?templates=windows,linux,macos,hugo,pycharm+all,vim,direnv + +### direnv ### +.direnv .envrc -*.swp -# Created by https://www.toptal.com/developers/gitignore/api/windows,linux,macos,hugo -# Edit at https://www.toptal.com/developers/gitignore?templates=windows,linux,macos,hugo ### Hugo ### # Generated files by hugo @@ -41,8 +42,7 @@ hugo.linux .LSOverride # Icon must end with two \r -Icon - +Icon # Thumbnails ._* @@ -67,6 +67,114 @@ Temporary Items # iCloud generated files *.icloud +### PyCharm+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + ### Windows ### # Windows thumbnail cache files Thumbs.db @@ -93,17 +201,4 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk -# End of https://www.toptal.com/developers/gitignore/api/windows,linux,macos,hugo - -# NixOS: -.envrc -shell.nix -.direnv - -# Python -.venv - -# murmeldin -overview.md - -/result +# End of https://www.toptal.com/developers/gitignore/api/windows,linux,macos,hugo,pycharm+all,vim,direnv diff --git a/.python-version b/.python-version deleted file mode 100644 index 2c07333..0000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.11 diff --git a/README.md b/README.md index 3b0af0f..5f72bd0 100644 --- a/README.md +++ b/README.md @@ -27,24 +27,20 @@ This is the website of the CCCB. 5. Point your browser to: -Every change you make on the project will be reflected in your browser as long -as `hugo serve` is running. +Every change you make on the project will be reflected in your browser as long as `hugo serve` is running. -The *"Nächste Veranstaltungen"* table on the home page is generated by -post-processing in `./build.sh`, not by Hugo, so it is **not** visible under -`hugo serve`. To preview the fully-built site (including the home-page -calendar), or to ready the site for upload, run: +The *"Nächste Veranstaltungen"* table on the home page is generated by post-processing in `./build.sh`, not by Hugo, so +it is **not** visible under `hugo serve`. To preview the fully built site (including the home-page calendar), or to +ready the site for upload, run: ```shell ./build.sh python3 -m http.server -d public 1313 ``` -`build.sh` generates `all.ics` and replaces the `CALENDAR` placeholder in -`index.html` with the upcoming-events table. It depends on Python with the -`icalendar`, `python-dateutil`, and `pytz` packages, plus a `de_DE.UTF-8` -locale (used to format weekday names). Inside `nix develop` these are -provided automatically. +`build.sh` replaces the `CALENDAR` placeholder in `index.html` with the upcoming-events table. It depends on Python +with the `icalendar`, `python-dateutil`, and `pytz` packages, plus a `de_DE.UTF-8` locale (used to format weekday +names). Inside `nix develop` these are provided automatically. To build with *nix*: `nix build '.?submodules=1#production-content'` @@ -55,7 +51,8 @@ To build with *nix*: `nix build '.?submodules=1#production-content'` 3. Commit (and push) your change. 4. ~~GitHub Actions is running the release workflow.~~ - If successful, check [Staging Website](https://staging.berlin.ccc.de/) if change is correct. -5. Create merge request to merge changes from `staging` to `production` branch. Ask somebody to check merge request or if small change, merge yourself. +5. Create a merge request to merge changes from `staging` to `production` branch. Ask somebody to check merge request or + if small change, merge yourself. 6. ~~GitHub Actions is running the release workflow.~~ - If successfull, check [Website](https://berlin.ccc.de/) if change is correct. 7. Profit! @@ -64,9 +61,12 @@ To build with *nix*: `nix build '.?submodules=1#production-content'` - After entering the shell with `nix develop`, hugo is available and `hugo serve` should work - Python including required packages will be available, so the `build.sh` should work without a venv -- You can build the staging and production builds with `nix build .#staging-content` and `nix build .#production-content` -- Do not update the nixpkgs branch - 25.05 contains a newer hugo version that is incompatible with the theme (last checked June 2025) +- You can build the staging and production builds with `nix build .#staging-content` and + `nix build .#production-content` +- Do not update the nixpkgs branch - 25.05 contains a newer hugo version that is incompatible with the theme (last + checked June 2025) --- Made with ❤️ and [Hugo](https://gohugo.io). + diff --git a/assets/js/calendar.js b/assets/js/calendar.js index ffb3c7e..18b4768 100644 --- a/assets/js/calendar.js +++ b/assets/js/calendar.js @@ -19,10 +19,10 @@ document.addEventListener('DOMContentLoaded', function() { if (colonIndex > -1) { let key = line.substring(0, colonIndex); let value = line.substring(colonIndex + 1); - + // Handle properties with parameters (like TZID) const baseKey = key.split(";")[0]; - + if (baseKey === "DTSTART") { event.start = value; event.startParams = key.includes(";") ? key.substring(key.indexOf(";") + 1) : null; @@ -46,14 +46,14 @@ document.addEventListener('DOMContentLoaded', function() { function parseDateString(icsDateStr) { // Handle different date formats if (!icsDateStr) return null; - + // For basic date format: YYYYMMDD if (icsDateStr.length === 8) { let year = icsDateStr.substring(0, 4); let month = icsDateStr.substring(4, 6); let day = icsDateStr.substring(6, 8); return `${year}-${month}-${day}`; - } + } // For datetime formats: YYYYMMDDTHHmmssZ or YYYYMMDDTHHmmss else if (icsDateStr.includes("T")) { let year = icsDateStr.substring(0, 4); @@ -67,34 +67,34 @@ document.addEventListener('DOMContentLoaded', function() { // Extract date components from different date formats function getDateComponents(icsDateStr) { if (!icsDateStr) return null; - + // Basic handling - extract YYYY, MM, DD regardless of format const year = parseInt(icsDateStr.substring(0, 4)); const month = parseInt(icsDateStr.substring(4, 6)) - 1; // 0-based months const day = parseInt(icsDateStr.substring(6, 8)); - + return { year, month, day }; } function expandRecurringEvents(event, year, month) { if (!event.rrule) return [event]; - + const rruleStr = event.rrule; - + // Get start date components const startComponents = getDateComponents(event.start); if (!startComponents) return [event]; - + const startDate = new Date( startComponents.year, startComponents.month, startComponents.day ); - + const rangeStart = new Date(year, month, 1); const rangeEnd = new Date(year, month + 1, 0); const expandedEvents = []; - + if (rruleStr.includes("FREQ=WEEKLY") && rruleStr.includes("BYDAY")) { const bydayMatch = rruleStr.match(/BYDAY=([^;]+)/); if (bydayMatch) { @@ -103,7 +103,7 @@ document.addEventListener('DOMContentLoaded', function() { 'MO': 1, 'TU': 2, 'WE': 3, 'TH': 4, 'FR': 5, 'SA': 6, 'SU': 0 }; const targetDay = dayMap[dayCode]; - + if (targetDay !== undefined) { // Create events for each matching day in the month let day = 1; @@ -112,13 +112,13 @@ document.addEventListener('DOMContentLoaded', function() { if (testDate.getDay() === targetDay && testDate >= startDate) { const newEvent = {...event}; const eventDate = formatDateForICS(testDate); - + // Preserve time portion from original event - const timePart = event.start.includes('T') ? + const timePart = event.start.includes('T') ? event.start.substring(event.start.indexOf('T')) : ''; - const endTimePart = event.end.includes('T') ? + const endTimePart = event.end.includes('T') ? event.end.substring(event.end.indexOf('T')) : ''; - + newEvent.start = eventDate + timePart; newEvent.end = eventDate + endTimePart; expandedEvents.push(newEvent); @@ -141,15 +141,15 @@ document.addEventListener('DOMContentLoaded', function() { const dayMap = { 'MO': 1, 'TU': 2, 'WE': 3, 'TH': 4, 'FR': 5, 'SA': 6, 'SU': 0 }; - + bydays.forEach(byday => { const occurrence = parseInt(byday) || 1; const dayCode = byday.slice(-2); const dayIndex = dayMap[dayCode]; - + let day = 1; let count = 0; - + while (day <= rangeEnd.getDate()) { const testDate = new Date(year, month, day); if (testDate.getDay() === dayIndex) { @@ -157,13 +157,13 @@ document.addEventListener('DOMContentLoaded', function() { if (count === occurrence || (occurrence < 0 && day > rangeEnd.getDate() + occurrence * 7)) { const newEvent = {...event}; const eventDate = new Date(year, month, day); - + // Preserve time portion from original event - const timePart = event.start.includes('T') ? + const timePart = event.start.includes('T') ? event.start.substring(event.start.indexOf('T')) : ''; - const endTimePart = event.end.includes('T') ? + const endTimePart = event.end.includes('T') ? event.end.substring(event.end.indexOf('T')) : ''; - + newEvent.start = formatDateForICS(eventDate) + timePart; newEvent.end = formatDateForICS(eventDate) + endTimePart; expandedEvents.push(newEvent); @@ -174,7 +174,7 @@ document.addEventListener('DOMContentLoaded', function() { }); } } - + return expandedEvents.length > 0 ? expandedEvents : [event]; } @@ -206,7 +206,7 @@ document.addEventListener('DOMContentLoaded', function() { function updateEventsForMonth(year, month) { // Clear existing events for this month view eventsByDate = {}; - + // Process each event, expanding recurring ones events.forEach(ev => { if (ev.rrule) { @@ -228,7 +228,7 @@ document.addEventListener('DOMContentLoaded', function() { // Check if this event belongs to current month view const eventYear = parseInt(dateKey.split('-')[0]); const eventMonth = parseInt(dateKey.split('-')[1]) - 1; - + if (eventYear === year && eventMonth === month) { if (!eventsByDate[dateKey]) { eventsByDate[dateKey] = []; @@ -238,7 +238,7 @@ document.addEventListener('DOMContentLoaded', function() { } } }); - + renderCalendar(year, month); } @@ -267,16 +267,16 @@ document.addEventListener('DOMContentLoaded', function() { } let cell = document.createElement("td"); cell.innerHTML = "" + day + ""; - + let dayStr = day < 10 ? "0" + day : day; let monthStr = (month + 1) < 10 ? "0" + (month + 1) : (month + 1); let dateKey = year + "-" + monthStr + "-" + dayStr; - + if (eventsByDate[dateKey]) { let dotsContainer = document.createElement("div"); dotsContainer.className = "event-dots-container"; cell.classList.add("has-event"); - + // Gruppe Events nach Typ const events = eventsByDate[dateKey]; const hasMembersOnly = events.some(e => e.summary.toLowerCase().includes("members only")); @@ -285,12 +285,12 @@ document.addEventListener('DOMContentLoaded', function() { const hasSpieleabend = events.some(e => e.summary.toLowerCase().includes("spieleabend")); const hasRegular = events.some(e => { const title = e.summary.toLowerCase(); - return !title.includes("members only") && - !title.includes("subbotnik") && - !title.includes("bastelabend") && + return !title.includes("members only") && + !title.includes("subbotnik") && + !title.includes("bastelabend") && !title.includes("spieleabend"); }); - + // Füge Dots entsprechend der Event-Typen hinzu if (hasMembersOnly) { let dot = document.createElement("div"); @@ -307,7 +307,7 @@ document.addEventListener('DOMContentLoaded', function() { dot.className = "event-dot event-dot-greenyellow"; dotsContainer.appendChild(dot); } - + cell.appendChild(dotsContainer); cell.dataset.dateKey = dateKey; cell.addEventListener("click", function() { @@ -336,8 +336,8 @@ document.addEventListener('DOMContentLoaded', function() { if (match && match[1]) { return `https://berlin.ccc.de/datengarten/${match[1]}/`; } - } - + } + // For other titles, convert to lowercase and use as path const slug = eventTitle.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]/g, ''); return `https://berlin.ccc.de/page/${slug}/`; @@ -355,13 +355,13 @@ document.addEventListener('DOMContentLoaded', function() { let eventTitle = document.createElement("div"); eventTitle.className = "event-title"; - + // Create a link for the event title let titleLink = document.createElement("h"); titleLink.textContent = ev.summary; titleLink.target = "_blank"; eventTitle.appendChild(titleLink); - + eventItem.appendChild(eventTitle); let eventTime = document.createElement("div"); @@ -372,7 +372,7 @@ document.addEventListener('DOMContentLoaded', function() { if (ev.description) { let eventDescription = document.createElement("div"); eventDescription.className = "event-description"; - + // Check if the description is a URL and make it a clickable link if (ev.description.trim().startsWith('http')) { let linkElement = document.createElement("a"); @@ -384,7 +384,7 @@ document.addEventListener('DOMContentLoaded', function() { } else { eventDescription.textContent = ev.description; } - + eventItem.appendChild(eventDescription); } @@ -409,7 +409,7 @@ document.addEventListener('DOMContentLoaded', function() { function formatTime(icsTimeStr) { // Format time for display if (!icsTimeStr) return ""; - + if (icsTimeStr.length === 8) { // All-day event return "Ganztägig"; @@ -431,20 +431,18 @@ document.addEventListener('DOMContentLoaded', function() { } // ICS-Datei abrufen und Events verarbeiten - fetch('/all.ics') + fetch('/calendars/all.ics') .then(response => response.text()) .then(data => { events = parseICS(data); - + // Initialize with current date let today = new Date(); currentYear = today.getFullYear(); currentMonth = today.getMonth(); - + // Process events for current month - - updateEventsForMonth(currentYear, currentMonth); - + updateEventsForMonth(currentYear, currentMonth); }) .catch(err => console.error('Fehler beim Laden der ICS-Datei:', err)); })(); diff --git a/assets/js/clubstatus.js b/assets/js/clubstatus.js index d87eb04..fffd93d 100644 --- a/assets/js/clubstatus.js +++ b/assets/js/clubstatus.js @@ -9,11 +9,11 @@ function timeDistanceDE(pastDate) { const hours = Math.floor(minutes / 60) const days = Math.floor(hours / 24) - if (days = 1) return `since ${days}d` + if (days === 1) return `since ${days}d` if (days > 1) return `since ${days}d` - if (hours = 1) return `since ${hours}h` + if (hours === 1) return `since ${hours}h` if (hours > 1) return `since ${hours}h` - if (minutes = 1) return `since ${minutes}min` + if (minutes === 1) return `since ${minutes}min` if (minutes > 1) return `since ${minutes}min` return `gerade eben` } diff --git a/build.sh b/build.sh index 6bc707a..625a262 100755 --- a/build.sh +++ b/build.sh @@ -1,12 +1,7 @@ #!/bin/sh -set -e -set -x +set -ex rm -rf public/ # delete old generated files hugo $(cat .hugo-params) -./tools/merge_cals.py -upcoming="$(tools/gen_upcoming.py static/all.ics 20 5 | tr '\n' ' ')" -cp static/all.ics public/all.ics -sed -i "s#CALENDAR#$upcoming#g" public/index.html diff --git a/config/_default/hugo.toml b/config/_default/hugo.toml index 13192d6..218ffbb 100644 --- a/config/_default/hugo.toml +++ b/config/_default/hugo.toml @@ -28,7 +28,7 @@ filename = "sitemap.xml" priority = 0.5 [permalinks] -post = "/post/:year/:month/:day/:title/" +post = "/post/:year/:month/:day/:slug/" [outputs] home = ["html", "rss", "json"] diff --git a/content/_index.md b/content/_index.md index 531fa85..4d73f01 100644 --- a/content/_index.md +++ b/content/_index.md @@ -25,6 +25,9 @@ description: "Startseite CCCB mit Kurzkalender" ### Nächste Veranstaltungen -CALENDAR + +
Weitere Termine findest du im [Veranstaltungskalender](/verein/calendar/). + + diff --git a/content/post/Neujahresempfang-2026/index.md b/content/post/Neujahresempfang-2026/index.md index 61844e1..17a6269 100644 --- a/content/post/Neujahresempfang-2026/index.md +++ b/content/post/Neujahresempfang-2026/index.md @@ -1,5 +1,6 @@ --- title: "Der Neujahresempfang 2026 #NJE26" +slug: "neujahresempfang-2026" date: 2026-03-05T12:00:00+01:00 showHero: false tags: ["NJE", "Ankündigung"] diff --git a/content/veranstaltungen/neujahresempfang.md b/content/veranstaltungen/neujahresempfang.md index 9a97796..98de614 100644 --- a/content/veranstaltungen/neujahresempfang.md +++ b/content/veranstaltungen/neujahresempfang.md @@ -10,4 +10,4 @@ menu: tag: ["Veranstaltung"] --- -Am 23. Mai lädt der Chaos Computer Club Berlin zum Neujahresempfang. [Hier geht es zur Infoseite!](https://berlin.ccc.de/post/2026/03/05/der-neujahresempfang-2026-%23nje26/) \ No newline at end of file +Am 23. Mai lädt der Chaos Computer Club Berlin zum Neujahresempfang. [Hier geht es zur Infoseite!](https://berlin.ccc.de/post/2026/03/05/neujahresempfang-2026/) \ No newline at end of file diff --git a/content/verein/calendar/index.md b/content/verein/calendar/index.md index fdac4e4..3fccf38 100644 --- a/content/verein/calendar/index.md +++ b/content/verein/calendar/index.md @@ -12,4 +12,15 @@ herostyle: big {{< calendar >}} -Keinen Termin mehr verpeilen? Einfach den [Veranstaltungskalender abonnieren](/all.ics)! +Keinen Termin mehr verpeilen? Einfach den [Veranstaltungskalender abonnieren](/calendars/all.ics)! + +Oder willst du nur den Kalender von bestimmten Events? + +- [Club Discordia](/calendars/Club_Discordia.ics) +- [Neujahresempfang](/calendars/Neujahresempfang.ics) +- [Datengarten](/calendars/Datengarten.ics) +- [Spieleabend](/calendars/Spieleabend.ics) +- [OpenWRT](/calendars/OpenWRT.ics) +- [Plenum](/calendars/Plenum.ics) +- [Amateurfunk](/calendars/Amateurfunk.ics) +- [Irreguläre Events](/calendars/Random.ics) diff --git a/flake.lock b/flake.lock index 2869045..33ab9db 100644 --- a/flake.lock +++ b/flake.lock @@ -2,16 +2,16 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1748995628, - "narHash": "sha256-bFufQGSAEYQgjtc4wMrobS5HWN0hDP+ZX+zthYcml9U=", + "lastModified": 1786313170, + "narHash": "sha256-9BG7OgUWdu0ONDO5X2q6+K4bsuBITkX/3W4nNJu1Ito=", "owner": "nixos", "repo": "nixpkgs", - "rev": "8eb3b6a2366a7095939cd22f0dc0e9991313294b", + "rev": "fcb8fcd6bf2d0adecae5bd491afaaaf8311b758d", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-24.11", + "ref": "nixos-26.05", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 39d9b6d..c29b73a 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ description = "A flake containing a development environment for the CCCB website."; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-26.05"; }; outputs = @@ -34,7 +34,7 @@ devShells = forAllSystems (import ./devShells.nix); - formatter = forAllSystems ({ pkgs, ... }: pkgs.nixfmt-rfc-style); + formatter = forAllSystems ({ pkgs, ... }: pkgs.nixfmt-tree); lib.mkWwwContent = { domain, system }: @@ -50,10 +50,6 @@ nativeBuildInputs = [ pkgs.hugo pkgs.glibcLocales - (pkgs.python3.withPackages (python-pkgs: [ - python-pkgs.icalendar - python-pkgs.pytz - ])) ]; # LOCALE_ARCHIVE = builtins.trace pkgs.glibcLocales "${pkgs.glibcLocales}/lib/locale/locale-archive"; @@ -62,11 +58,6 @@ buildPhase = '' mkdir -p public hugo --baseURL=https://${domain}/ - - python3 ./tools/merge_cals.py - upcoming="$(python3 tools/gen_upcoming.py static/all.ics 20 5 | tr '\n' ' ')" - cp static/all.ics public/all.ics - sed -i "s#CALENDAR#$upcoming#g" public/index.html ''; # Install phase - copy the public directory to the output diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index c61ba7f..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -icalendar==5.0.7 -pytz \ No newline at end of file diff --git a/static/js/upcoming.js b/static/js/upcoming.js new file mode 100644 index 0000000..6b7a711 --- /dev/null +++ b/static/js/upcoming.js @@ -0,0 +1,113 @@ +import ICAL from "https://unpkg.com/ical.js/dist/ical.min.js"; + +/** + * Parse an ICS calendar and return upcoming event occurrences. + * + * @param {string} icsText The contents of the .ics file + * @param {Date} now Events must start after this date + * @param {number} maxEvents Maximum number of events to return + * @param {number} maxDays Maximum number of days into the future + * @returns {{start: Date, name: string, url: string}[]} + */ +function getUpcomingEvents(icsText, now, maxEvents, maxDays) { + const jcal = ICAL.parse(icsText); + const calendar = new ICAL.Component(jcal); + + const end = new Date(now.getTime()); + end.setDate(end.getDate() + maxDays); + + const events = []; + + for (const component of calendar.getAllSubcomponents("vevent")) { + const event = new ICAL.Event(component); + + if (!event.startDate) { + continue; + } + + if (event.isRecurring()) { + const iterator = event.iterator(); + + while (true) { + const occurrence = iterator.next(); + + if (!occurrence) { + break; + } + + const start = occurrence.toJSDate(); + + // Recurrences are chronological, so we're done + // once we pass the end of our search window. + if (start > end) { + break; + } + + if (start > now) { + events.push({ + start, + name: event.summary ?? "", + url: event.url ?? "", + }); + } + } + } else { + const start = event.startDate.toJSDate(); + + if (start > now && start <= end) { + events.push({ + start, + name: event.summary ?? "", + url: event.url ?? "", + }); + } + } + } + + // We have occurrences from multiple events, so sort them + // before applying the maximum event count. + events.sort((a, b) => a.start - b.start); + + return events.slice(0, maxEvents); +} + +document.addEventListener("DOMContentLoaded", () => { + const ics = "/calendars/all.ics"; + const max_days = 20; + const max_items = 5; + + const now = new Date(); + + const table = document.getElementById("upcoming"); + fetch(ics) + .then(response => response.text()) + .then(icsText => { + getUpcomingEvents(icsText, now, max_items, max_days).forEach(event => { + const row = document.createElement("tr"); + + const colBegin = document.createElement("td"); + + const formattedStart = event.start.toLocaleString("de-DE", { + weekday: "long", + day: "2-digit", + month: "2-digit", + hour: "2-digit", + minute: "2-digit", + }).replace(",", ""); + + colBegin.innerText = `${formattedStart.replace(" ", ", ")} Uhr`; + row.appendChild(colBegin); + + const colName = document.createElement("td"); + + const a = document.createElement("a"); + a.href = event.url; + a.text = event.name; + + colName.appendChild(a); + row.appendChild(colName); + + table.appendChild(row); + }); + }); +}); diff --git a/tools/gen_upcoming.py b/tools/gen_upcoming.py deleted file mode 100755 index 31763f7..0000000 --- a/tools/gen_upcoming.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import logging -import locale -from dateutil.parser import parse as _parse -from datetime import datetime, timedelta -from dateutil.rrule import rruleset, rrulestr - -import icalendar - - -def parse(value): - # Some templates emit DTSTART with a trailing "Z" (e.g. 20260507T190000Z) - # which produces tz-aware datetimes, while others emit naive local times. - # Normalize to naive so comparisons and sorting don't mix the two. - dt = _parse(value) - if dt.tzinfo is not None: - dt = dt.replace(tzinfo=None) - return dt - - -def vevent_to_event(event, rrstart=None): - if rrstart == None: - begin = parse(event["DTSTART"].to_ical()) - else: - begin = rrstart - - return { - "name": event["SUMMARY"].to_ical(), - "url": event["URL"].to_ical(), - "begin": begin - } - - -def parse_single_event(event, start, end): - logging.info(f"Processing single event {event['SUMMARY'].to_ical().decode('utf-8')}") - dtstart = parse(event["DTSTART"].to_ical()) - if dtstart >= start and dtstart < end: - return vevent_to_event(event) - - -def parse_recurring_event(event, start, end): - logging.info(f"Processing recurring event {event['SUMMARY'].to_ical().decode('utf-8')}") - dtstart = parse(event["DTSTART"].to_ical()) - rs = rruleset() - # dtstart is normalized to naive local time above; pass ignoretz so a - # tz-aware UNTIL (RFC 5545 requires UTC for it) is treated as naive too, - # otherwise dateutil rejects the naive/aware mismatch. - rs.rrule(rrulestr(event["RRULE"].to_ical().decode("utf-8"), dtstart=dtstart, ignoretz=True)) - if "EXDATE" in event.keys(): - for exdate in event["EXDATE"]: - rs.exdate(parse(exdate.to_ical())) - - events = [] - for date in list(rs): - if date >= start and date < end: - events.append(vevent_to_event(event, date)) - - return events - - -def find_events(icsfilestr, start, end, num): - with open(icsfilestr, "r") as icsfile: - cal = icalendar.Calendar.from_ical(icsfile.read()) - - events = [] - for event in cal.subcomponents: - if event.name == "VEVENT": - if "RRULE" in event.keys(): - events.extend(parse_recurring_event(event, start, end)) - else: - ev = parse_single_event(event, start, end) - if ev is not None: - events.append(ev) - - events = sorted(events, key=lambda k: k["begin"]) - events = events[0:num] - - return events - - -def format_events(events): - print("") - for event in events: - print( - "" - f"" - f"" - "" - ) - print("
{event['begin'].strftime('%A, %d.%m um %H:%M Uhr')}{event['name'].decode('utf-8')}
") - - -if __name__ == "__main__": - if len(sys.argv) < 3: - print(f"Usage: {sys.argv[0]} calendar max_days max_items") - sys.exit(-1) - - locale.setlocale(locale.LC_TIME, "de_DE.UTF-8") - calendar = sys.argv[1] - max_days = int(sys.argv[2]) - max_items = int(sys.argv[3]) - - now = datetime.now() - events = find_events(calendar, now, now + timedelta(days=max_days), max_items) - format_events(events) - diff --git a/tools/merge_cals.py b/tools/merge_cals.py deleted file mode 100755 index 136904e..0000000 --- a/tools/merge_cals.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python3 - -from glob import glob - -import pytz -import icalendar - - -calendars = [] -merged = icalendar.Calendar() -merged.add("prodid", "-//CCCB Calendar Generator//berlin.ccc.de//") -merged.add("version", "2.0") - -for icsfilestr in glob("public/*/**/*.ics", recursive=True): - with open(icsfilestr, "r") as icsfile: - print(f"Importing {icsfilestr}") - calendars.append(icalendar.Calendar.from_ical(icsfile.read())) - -for calendar in calendars: - for event in calendar.subcomponents: - if event.name != "VEVENT": - continue - if "DTSTART" not in event: - continue - merged.add_component(event) - -outfile = "static/all.ics" -with open(outfile, "wb") as f: - print(f"writing to {outfile}...") - f.write(merged.to_ical()) - From 2696f0af4e84ca034a78b36d827d6742dc856ce0 Mon Sep 17 00:00:00 2001 From: xengi Date: Wed, 12 Aug 2026 02:06:53 +0200 Subject: [PATCH 36/38] python is not needed anymore Signed-off-by: xengi --- .forgejo/workflows/deploy.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index 1813837..057a8f9 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -14,14 +14,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Install dependencies - run: apk --no-cache add hugo python3 py3-pip git openssh-client rsync + run: apk --no-cache add hugo git openssh-client rsync - name: Check versions run: | cat /etc/os-release git version hugo version - python --version rsync --version ssh -V @@ -33,9 +32,6 @@ jobs: git clone -b $GIT_BRANCH --recursive https://git.berlin.ccc.de/cccb-website-team/www.git . git status - - name: Install Python dependencies - run: python -m pip install -r requirements.txt --break-system-packages - - name: Render site run: ./build.sh From f6b5413d1939ea927c8d0e467cb212a077b986f2 Mon Sep 17 00:00:00 2001 From: xengi Date: Wed, 12 Aug 2026 02:26:23 +0200 Subject: [PATCH 37/38] Delete .forgejo/workflows/miau.yaml --- .forgejo/workflows/miau.yaml | 58 ------------------------------------ 1 file changed, 58 deletions(-) delete mode 100644 .forgejo/workflows/miau.yaml diff --git a/.forgejo/workflows/miau.yaml b/.forgejo/workflows/miau.yaml deleted file mode 100644 index 1813837..0000000 --- a/.forgejo/workflows/miau.yaml +++ /dev/null @@ -1,58 +0,0 @@ -name: deploy blog - -on: - workflow_dispatch: - schedule: - - cron: '0 10 * * *' # daily at 10:00 - push: - branches: - - staging - - production - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - name: Install dependencies - run: apk --no-cache add hugo python3 py3-pip git openssh-client rsync - - - name: Check versions - run: | - cat /etc/os-release - git version - hugo version - python --version - rsync --version - ssh -V - - - name: Set envionment vars - run: echo "GIT_BRANCH=${{ forgejo.event_name == 'schedule' && 'production' || forgejo.ref_name }}" >> "$FORGEJO_ENV" - - - name: Checkout repository - run: | - git clone -b $GIT_BRANCH --recursive https://git.berlin.ccc.de/cccb-website-team/www.git . - git status - - - name: Install Python dependencies - run: python -m pip install -r requirements.txt --break-system-packages - - - name: Render site - run: ./build.sh - - - name: Setup SSH - run: | - mkdir -p ~/.ssh - printf "%s" "${{ secrets.KNOWN_HOSTS }}" | base64 -d > ~/.ssh/known_hosts - printf "%s" "${{ env.GIT_BRANCH == 'production' && secrets.SSH_PRIVATE_KEY_PRODUCTION || secrets.SSH_PRIVATE_KEY_STAGING }}" | base64 -d > ~/.ssh/id_ed25519 - chmod 600 ~/.ssh/id_ed25519 - ssh-keygen -f ~/.ssh/id_ed25519 -y > ~/.ssh/id_ed25519.pub - cat ~/.ssh/id_ed25519.pub - - - name: Rsync rendered site - # TODO: add --delete - run: rsync -var -e 'ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes' ./public/ deploy@www.berlin.ccc.de:${{ env.GIT_BRANCH == 'production' && '/srv/http/www/' || '/srv/http/www-staging/' }} - - - name: Cleanup - if: ${{ always() }} - run: rm -rf ~/.ssh - From e93b399854efb8d7147e44eeca563ed34c7f796d Mon Sep 17 00:00:00 2001 From: xengi Date: Fri, 21 Aug 2026 21:36:22 +0200 Subject: [PATCH 38/38] Update .forgejo/workflows/deploy.yaml Signed-off-by: xengi --- .forgejo/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/deploy.yaml b/.forgejo/workflows/deploy.yaml index 057a8f9..04e8003 100644 --- a/.forgejo/workflows/deploy.yaml +++ b/.forgejo/workflows/deploy.yaml @@ -11,7 +11,7 @@ on: jobs: deploy: - runs-on: ubuntu-latest + runs-on: alpine-latest steps: - name: Install dependencies run: apk --no-cache add hugo git openssh-client rsync