No description
  • Go 99.4%
  • Dockerfile 0.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-06-08 09:45:37 +02:00
.claude commit message 2026-02-23 11:13:11 +01:00
.gitignore commit message 2026-02-23 11:13:11 +01:00
cache.go commit message 2026-02-23 11:13:11 +01:00
caldav.go fix: rustical caldav 2026-06-08 09:27:57 +02:00
caldav_test.go fix: rustical caldav 2026-06-08 09:27:57 +02:00
calendar.go fix: rustical caldav 2026-06-08 09:33:37 +02:00
calendar_test.go fix: rustical caldav 2026-06-08 09:33:37 +02:00
Dockerfile feat: caldav 2026-06-08 09:16:53 +02:00
go.mod feat: caldav 2026-06-08 09:16:53 +02:00
go.sum feat: caldav 2026-06-08 09:16:53 +02:00
main.go feat: skip cancelled 2026-06-08 09:45:37 +02:00
main_test.go feat: skip cancelled 2026-06-08 09:45:37 +02:00
README.md feat: skip cancelled 2026-06-08 09:45:37 +02:00
sync.go feat: skip cancelled 2026-06-08 09:45:37 +02:00
untis.go feat: caldav 2026-06-08 09:16:53 +02:00
untis_test.go feat: caldav 2026-06-08 09:16:53 +02:00
untiscal commit message 2026-02-23 11:13:11 +01:00

untiscal

untiscal fetches a WebUntis timetable and exposes it as an ICS calendar feed. It can also push the next two weeks of events into a CalDAV calendar.

Configuration

The WebUntis settings are required for both the ICS feed and CalDAV sync:

UNTIS_SERVER=example.webuntis.com
UNTIS_SCHOOL=ExampleSchool
UNTIS_USERNAME=...
UNTIS_PASSWORD=...
UNTIS_TIMEZONE=Europe/Berlin

Optional feed/server settings:

LISTEN_ADDR=:8080
CACHE_TTL=5m
FETCH_WEEKS=4
CALENDAR_NAME="Untis Timetable"
TOKEN_SECRET=...

If TOKEN_SECRET is set, requests to the feed must include it as a query parameter:

http://localhost:8080/feed.ics?token=...

Without TOKEN_SECRET, the feed is available at:

http://localhost:8080/feed.ics

CalDAV Push

Enable CalDAV sync with:

CALDAV_ENABLED=true
CALDAV_URL=https://cal.gametec-live.com/caldav
CALDAV_USERNAME=GameTec_live
CALDAV_PASSWORD=...
CALDAV_CALENDAR=Untis
CALDAV_SYNC_INTERVAL=6h
CALDAV_SKIP_CANCELLED=false

The sync runs once on startup and then repeats every CALDAV_SYNC_INTERVAL. Each run:

  • Fetches WebUntis events from now through the next 14 days.
  • Pushes each event to the configured CalDAV calendar using a stable Untis UID.
  • Skips cancelled WebUntis events if CALDAV_SKIP_CANCELLED=true.
  • Deletes only old Untiscal-created CalDAV events older than 14 days.
  • Leaves manually created or non-Untiscal calendar events untouched.

Keep CALDAV_PASSWORD in the runtime environment or secret manager. Do not commit it to the repository.

Run Locally

export UNTIS_SERVER=example.webuntis.com
export UNTIS_SCHOOL=ExampleSchool
export UNTIS_USERNAME=...
export UNTIS_PASSWORD=...

go run .

With CalDAV enabled:

export CALDAV_ENABLED=true
export CALDAV_URL=https://cal.gametec-live.com/caldav
export CALDAV_USERNAME=GameTec_live
export CALDAV_PASSWORD=...
export CALDAV_CALENDAR=Untis
export CALDAV_SKIP_CANCELLED=true

go run .

Docker

docker build -t untiscal .
docker run --rm -p 8080:8080 \
  -e UNTIS_SERVER=example.webuntis.com \
  -e UNTIS_SCHOOL=ExampleSchool \
  -e UNTIS_USERNAME=... \
  -e UNTIS_PASSWORD=... \
  -e CALDAV_ENABLED=true \
  -e CALDAV_URL=https://cal.gametec-live.com/caldav \
  -e CALDAV_USERNAME=GameTec_live \
  -e CALDAV_PASSWORD=... \
  -e CALDAV_CALENDAR=Untis \
  -e CALDAV_SKIP_CANCELLED=true \
  untiscal

For RustiCal, use the CalDAV root path /caldav as shown above. If the host root is configured instead, untiscal will also try RustiCal's standard /caldav and /caldav-compat discovery paths automatically.

Test

go test ./...