Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d50139395b | |||
| 4ad46ab774 | |||
| fe85bebb59 | |||
| 8e280c350b | |||
| 991e9f1622 | |||
| f82df9e156 | |||
| 3261862f52 | |||
| 1cda263641 | |||
| e36b498092 | |||
| 0f27c16b64 | |||
| 8d66fffcf0 | |||
| f744215c13 | |||
| 654e53e8f5 | |||
| e43f3ccda9 | |||
| 4896fee8d2 | |||
| 430662fa44 | |||
| c145161bc4 | |||
| 0b67ad4cfb | |||
| aebd59d283 | |||
| b27b3899ce | |||
| 89f6c9198d | |||
| 74229708d2 | |||
| de5369ac2b | |||
| 417f5c73b7 | |||
| db91e8d7d3 | |||
| fba9457d44 | |||
| 289d8b9642 | |||
| 5242c3c2a3 | |||
| f908c9526f | |||
| 5e9ac72fb0 |
14 changed files with 69 additions and 61 deletions
|
|
@ -1,6 +1,8 @@
|
||||||
name: deploy blog
|
name: deploy blog
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 10 * * *' # daily at 10:00
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- staging
|
- staging
|
||||||
|
|
|
||||||
22
README.md
22
README.md
|
|
@ -27,10 +27,24 @@ This is the website of the CCCB.
|
||||||
|
|
||||||
5. Point your browser to: <http://localhost:1313/>
|
5. Point your browser to: <http://localhost:1313/>
|
||||||
|
|
||||||
To ready your site for upload, run `./build.sh`, which also generates `all.ics`
|
Every change you make on the project will be reflected in your browser as long
|
||||||
and adds the calendar table to `index.html`.
|
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'`
|
To build with *nix*: `nix build '.?submodules=1#production-content'`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
else if (rruleStr.includes("FREQ=MONTHLY") && rruleStr.includes("BYDAY")) {
|
else if (rruleStr.includes("FREQ=MONTHLY") && rruleStr.includes("BYDAY")) {
|
||||||
const bydayMatch = rruleStr.match(/BYDAY=([^;]+)/);
|
const bydayMatch = rruleStr.match(/BYDAY=([^;]+)/);
|
||||||
if (bydayMatch) {
|
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 bydays = bydayMatch[1].split(',');
|
||||||
const dayMap = {
|
const dayMap = {
|
||||||
'MO': 1, 'TU': 2, 'WE': 3, 'TH': 4, 'FR': 5, 'SA': 6, 'SU': 0
|
'MO': 1, 'TU': 2, 'WE': 3, 'TH': 4, 'FR': 5, 'SA': 6, 'SU': 0
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ draft: true
|
||||||
|
|
||||||
|
|
||||||
{{< alert "circle-info" >}}
|
{{< 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 schon mal 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 >}}
|
{{< /alert >}}
|
||||||
|
|
|
||||||
20
content/veranstaltungen/didit.md
Normal file
20
content/veranstaltungen/didit.md
Normal file
|
|
@ -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/).
|
||||||
|
|
@ -2,9 +2,8 @@
|
||||||
title: "Neujahresempfang"
|
title: "Neujahresempfang"
|
||||||
subtitle: "#NJE 26"
|
subtitle: "#NJE 26"
|
||||||
date: 2025-03-05T18:00:00+02:00
|
date: 2025-03-05T18:00:00+02:00
|
||||||
dtstart: 20250523T180000
|
dtstart: 20260523T180000
|
||||||
dtend: 20250524T100000
|
dtend: 20260524T100000
|
||||||
rrule: "FREQ=MOTHLY;BYDAY=4SA;WKST=MO"
|
|
||||||
menu:
|
menu:
|
||||||
main:
|
main:
|
||||||
parent: "Veranstaltungen"
|
parent: "Veranstaltungen"
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
title: "OpenWrt"
|
title: "OpenWrt"
|
||||||
subtitle: "OpenWrt Stammtisch"
|
subtitle: "OpenWrt Stammtisch"
|
||||||
date: 2025-01-08T20:00:00+02:00
|
date: 2025-01-08T20:00:00+02:00
|
||||||
dtstart: 20250115T200000
|
dtstart: 20251119T200000
|
||||||
dtend: 20250115T230000
|
dtend: 20251119T230000
|
||||||
rrule: "FREQ=MONTHLY;BYDAY=3WE;WKST=MO"
|
rrule: "FREQ=MONTHLY;INTERVAL=3;BYDAY=3WE;WKST=MO"
|
||||||
menu:
|
menu:
|
||||||
main:
|
main:
|
||||||
parent: "Veranstaltungen"
|
parent: "Veranstaltungen"
|
||||||
|
|
@ -13,7 +13,7 @@ tag: ["Veranstaltung"]
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
**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.
|
Das OpenWrt Meetup richtet sich an alle die OpenWrt benutzen oder benutzen wollen aber auch Leute die an OpenWrt entwickeln.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ tag: ["Veranstaltung"]
|
||||||
**Jeden 2. und 4. Samstag im Monat ist ab 17 Uhr Spieleabend im Club.**
|
**Jeden 2. und 4. Samstag im Monat ist ab 17 Uhr Spieleabend im Club.**
|
||||||
|
|
||||||
{{< alert "circle-info" >}}
|
{{< 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 schon mal 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 >}}
|
{{< /alert >}}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ Der Begriff [Subbotnik](https://de.wikipedia.org/wiki/Subbotnik) ist eine in Sow
|
||||||
---
|
---
|
||||||
|
|
||||||
{{< alert "circle-info" >}}
|
{{< 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 schon mal 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 >}}
|
{{< /alert >}}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
{{ block "main" . }}{{ .Content }}{{ end }}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -3,13 +3,23 @@
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
import locale
|
import locale
|
||||||
from dateutil.parser import parse
|
from dateutil.parser import parse as _parse
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from dateutil.rrule import rruleset, rrulestr
|
from dateutil.rrule import rruleset, rrulestr
|
||||||
|
|
||||||
import icalendar
|
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):
|
def vevent_to_event(event, rrstart=None):
|
||||||
if rrstart == None:
|
if rrstart == None:
|
||||||
begin = parse(event["DTSTART"].to_ical())
|
begin = parse(event["DTSTART"].to_ical())
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue