Repository navigation
feat: hide courses by teacher, room, time slot or one at a time - #222
Merged
Merged
Conversation
The blocklist only hid courses by title. Add 4 more filters, applied by the API so the calendar and the ICS feed stay the same: - teacher: keyword in the description (sources have no teacher field) - room: keyword in the location - weekly time slot: weekday and start/end time, read in the timezone the calendar shows (`tz`, default Europe/Paris) - one course: hidden from the event details, keyed by a short hash of its title and start time, because Celcat UIDs end with the event's position in the file Filters are stored in one `eventFilters` pref (JSON string, new `event_filters` column) and synced like customGroups. The blocklist pref and old `?blocklist=` links keep working. Closes #216 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- match room and teacher filters on the raw text too, so "joker" hides "salle joker à distance" courses - "Cacher ce cours" always hides one session, never the whole title - slot filters ignore all-day and multi-day events - build the ICS cache key with JSON.stringify so values cannot collide - read the timezone in filterParams only when slots exist - show hidden course dates in the calendar timezone - drop the unused hasEventFilters and share parseList with ics.ts Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #216
You can now hide courses in 4 more ways, on top of the existing "hide by name" list:
Where filtering happens
All filters run on the server, in
getFormattedEvents, the same place as the blocklist. This keeps one code path, and the ICS feed hides the same courses as the app. The share modal builds the ICS link from the samefilterParamsas the events requests.Data shape and sync
packages/libs/src/event-filters.ts, used by the web app and the API:{ teachers: string[], rooms: string[], slots: { day, start, end }[], hidden: { key, title, start }[] }settings.eventFiltersand syncs them as oneeventFiltersuser pref, a JSON string likecustomGroups. The server validates it witheventFiltersInput, andprefsMetaaccepts the new keyevent_filterstext column (migration0009). I added the column by hand inschemas/auth.tsbecausegenerate-better-authalso rewrote the passkey table (unrelated drift from the newer better-auth version).generate-drizzlethen produced a one-lineALTER TABLE?blocklist=ICS links keep workingQuery params
/api/plannings/:fullIdand/api/icsboth accept these params:blocklist,teachersandrooms: comma-separated keywords, case-insensitiveslots: for example4-1400-1800(ISO weekday 1 = Monday)tz: the timezone of the slots. The app sends it only when slots exist, set to the timezone the calendar shows. The default is Europe/Parishidden: comma-separated keysThe ICS cache key now includes every filter, sorted, so the same filters in any order use the same cache entry.
Why one course is hidden by a hash, not by UID
I checked real sources. UIDs are unique in every sampled planning, but Celcat UIDs end with the event's position in the file (
3202836-4,3202813-13). The suffix changes when an event is added or removed earlier in the feed, so a hide by UID would silently stop working. Instead, the key is a 32-bit FNV-1a hash of the lowercase title and the start time, 6 or 7 characters in base36. The benefits:When you hide a new course, the app removes hidden courses from past days, so the list stays short.
Other changes
TagInputnow makes a unique helper id withuseId(), because the settings page shows 3 of themAGENTS.mdabout the filtersTested
bun run lint-fix && bun run lint && bun run typecheck && bun run test:unit: 188 pass, 0 failtest/event-filters.test.ts: normalising, slot encoding, query parsing, the matcher (title, teacher, room, hidden key, slot overlap, summer time, other timezone) and the cache keytest/web.useSettings.eventFilters.test.ts: sync encoding, query params, and removing past hidden coursestest/ics.test.tsandtest/plannings.routes.test.ts: route tests for each filtertest/api.authValidators.test.ts:eventFiltersInputand theprefsMetakeyapps/apibun run build: the bundle picks up@libs/event-filtersbun devin Chrome, in an isolated context, on IUT Nantes INFO1-G1 (Celcat):hidden=h8ueyband the course disappears. It then appears in the settings, and "Réafficher" brings it backsimonneau, roomamphiand slot Wednesday 08:00–10:00: each change reloads with the right params, and the matching courses disappear. Nothing matching remainscurlon the feed: 231 events without filters, 203 with an oldblocklist=anglaislink, 165 with all filters, and no remaining "SIMONNEAU" or "Amphi"Not tested live: account sync. I could not sign in through Discord or GitHub from the test browser. Sync uses the same
syncPrefpath ascustomGroups, and the unit tests cover the encoding and the server validator.🤖 Generated with Claude Code