renovate Bot f9a370d328
renovate/stability-days Updates have met minimum release age requirement
fix(deps): update module modernc.org/sqlite to v1.60.1
2026-10-11 01:08:49 +00:00

usoscal

USOS timetable as a calendar feed that keeps the past.

The iCalendar export built into USOS only contains what is ahead of today, so classes vanish from the calendar as soon as they pass. usoscal signs a student in through USOS, gives them a private .ics address and, when they ask for it, keeps every class it has ever seen.

make env       # .env and docker-compose.override.yml from the examples
make recreate  # the services in COMPOSE_PROFILES

make fmt and make check format, lint and test; without a local Go they run in the golang image.

Configuration

Everything comes from .env:

Variable Meaning
PUBLIC_URL Address the service is opened at, used for the OAuth callback and for calendar addresses
USOS_CONSUMER_KEY, USOS_CONSUMER_SECRET API key of the USOS installation, issued at <usos>/developers/
TOKEN_ENC_KEY 32 random bytes in base64 (openssl rand -base64 32), encrypts stored tokens
USOS_BASE_URL USOS API installation, https://usosapps.put.poznan.pl by default
SYNC_INTERVAL How often each timetable is refreshed, 24h by default
STORAGE_ROOT Host directory of the SQLite file, ./storage by default

Changing TOKEN_ENC_KEY makes every stored token unreadable: people sign in again and get a new calendar address.

What a user gets

One page. Signed out, it explains the service and has a single button. Signed in, it shows:

  • the calendar address, with a button to issue a new one and a button to revoke it, both of which stop the current address at once;
  • the archive checkbox: on, past classes stay and earlier terms are fetched once; off, the stored past is deleted;
  • when the timetable was last refreshed;
  • sign-out, which revokes the token in USOS, deletes the stored tokens, stops the calendar address and, if asked, deletes the timetable.

An event carries the course name with the class type as its title, the room with the building and its postal address as the location, and the group, the lecturers and the USOS link in the description.

How it works

One Go binary and one SQLite file. internal/usos is the OAuth 1.0a client, internal/syncer refreshes timetables, internal/ical writes the feed, internal/server is the page and the feed endpoint, internal/store is the database, internal/seal is the encryption.

The feed is served from the database, never by calling USOS on a calendar request. Once per SYNC_INTERVAL the syncer asks USOS for every week from today to the end of the running semester and replaces those weeks with what it got, so a class that was moved or cancelled changes in the feed too. Days that have passed are never asked for again: with the archive on they stay as they were last seen, with it off they are deleted. Turning the archive on walks backwards week by week until USOS has returned nothing for half a year.

What USOS allows and where it misbehaves is written down in docs/usos-api.md, what is stored and how it is protected in docs/security.md.

S
Description
USOS timetable as a calendar feed that keeps the past
Readme
78 KiB
0 Stars 2 Watchers 0 Forks
Languages
Go 90.8%
HTML 7.2%
Makefile 1.5%
Dockerfile 0.5%