Commit Graph

70 Commits

Author SHA1 Message Date
Jakub Zych
67bc3eb944 build: rebuild the student app (pulpit reading links) 2026-10-27 01:46:33 +01:00
Jakub Zych
ff2f97eb2b feat: materials by zjazd in the student API and admin
The material admin form gets the "Na zjazd" picker, every student
material JSON carries meeting_id, and GET /materials accepts meeting=
inside the published-only scope, so the Pulpit hero can list the
zjazd's materials next to its readings.
2026-10-27 01:44:38 +01:00
Jakub Zych
3241cc9894 feat: zjazd (meeting) on readings and materials
The Pulpit hero lists what to read for the current or next zjazd, so
readings and materials get a nullable meeting_id (FK to jz_bm_meetings,
ON DELETE SET NULL, indexed). The reading admin form gets a "Na zjazd"
picker, the student reading JSON carries meeting_id, and the management
/readings records filter and validate it.
2026-10-27 01:41:48 +01:00
8843e73f98 chore: require golem15.chat v0.1.2 2026-10-26 20:31:54 +01:00
3a7bc46f08 build: rebuild the student app (full-width pages) 2026-10-26 20:08:59 +01:00
35ef575b08 build: rebuild the student app (chat review fixes)
Per-message attachment total, deleted-while-offline messages, nested
code spans in links and /\host site paths.
2026-10-26 19:40:22 +01:00
be3769d75f chore: require golem15.chat v0.1.1 2026-10-26 19:39:54 +01:00
0ff943b6af fix: keep DM participant rows when a user leaves the chat group
The participant sync and the non-member prune now remove only ogólny's
rows. A user taken out of studenci, even briefly, keeps their DMs (the
live membership check denies access while they are out) and gets them
back when re-added, instead of losing them for good.
2026-10-26 19:34:53 +01:00
8b81295458 fix: revoke chat access as soon as a user leaves the chat group
The BM chat context implements golem15.chat's LiveMembership, so every
participant check also requires chat-group membership: a removed user
loses # ogólny, their DMs, uploads, subscriptions and chat:message
delivery at once instead of after the next participant sync.
2026-10-26 19:33:52 +01:00
a840d0ad02 fix: enforce the chat's per-message upload total
jz.bm.chat.max_upload_bytes is now handed to golem15.chat as the total
size of one message's attachments, so the server enforces the limit the
bootstrap advertises.
2026-10-26 19:32:07 +01:00
cf32fa18b9 build: rebuild the student app (chat) 2026-10-26 17:17:54 +01:00
2681d304e2 feat: delete-only chat moderation and embed search and resolve
- ChatContext implements golem15.chat's MessageModerator: moderator
  group members who are chat members delete in group conversations
  only, never in DMs
- GET /chat/embeds?type=deadline|class|reading&q= (members only,
  at most 20 rows, escaped ILIKE, q at most 100 characters)
- POST /chat/embeds/resolve {refs} (members only, at most 50 distinct
  refs, 8 KiB body): current data or null per ref
2026-10-26 16:07:26 +01:00
ac4c2e6f73 test: cover chat moderation and the embed endpoints
- CanModerateMessage: group conversations only, chat members only
- parseEmbedRefs, embedKey, escapeLike
- /chat/embeds and /chat/embeds/resolve: 401, 422 before the
  database, 503 without one
2026-10-26 16:05:33 +01:00
eea171cee6 feat: open realtime tokens to chat members
The connection-token route is guarded by jz.bm.realtime-access instead
of presentations.realtime-owner: chat-group members get a token, and
when golem15.presentations is active so does everyone its owner guard
lets through (looked up by name among the activated plugins, no import).
Everyone else gets 401, 403 or 503 in the guard's error shape. The
realtime routes mount when golem15.chat or golem15.presentations is
active. /_chat, /_chatchannels and /_chatbots are reserved prefixes of
the student app.
2026-10-26 15:49:29 +01:00
cb7ba7ec8a test: cover the realtime access guard and chat prefixes
jz.bm.realtime-access admits chat-group members and, through
golem15.presentations' owner guard, presentation owners; everyone else
gets 401, 403 or 503 with Cache-Control no-cache, private. /_chat,
/_chatchannels and /_chatbots are reserved for the APIs.
2026-10-26 15:48:07 +01:00
0642fb1d08 feat: chat bootstrap, members and group sync
GET /_bm/api/v1/chat gives a chat-group member ogólny (the bm/1 group
conversation, adopted once as the system default channel under an
advisory lock), its unread and mention counts, the member's DMs newest
message first, the moderator flag and the composer limits. Every member
bootstrap syncs participants with the group: missing members join
ogólny, users no longer in the group lose their rows in every bm/1
conversation. A non-member gets only member:false and is pruned.

GET /_bm/api/v1/chat/members lists members (id, name, surname, handle,
is_bot from golem15.chatbots when active) and assigns missing handles;
non-members get 404.

The chatchannels access policy (ChatAccess) is installed from a
database hook: bm/1 for members only, nobody manages channels.
bm:chat-sync creates the groups when missing, syncs and assigns
handles. Migration 20261026130000_seed_jz_bm_chat_groups creates
studenci and moderatorzy without members; its rollback keeps them.
2026-10-26 15:46:13 +01:00
07d67be1e7 test: cover the chat access policy and bootstrap guards
ChatAccess admits only chat-group members to context bm/1 and manages
nothing; the chat context oversees nothing and its loader knows only
id 1; /chat and /chat/members need a caller and a database. The
migration count rises to 15 for the chat group seed.
2026-10-26 15:42:53 +01:00
64601f6817 feat: host the BM chat context
When golem15.chat is active, Boot registers the context alias bm (id 1)
on its registry. Membership is the user group jz.bm.chat.group (default
studenci); CanOverseeChats is always false, so nobody reads other
people's DMs or edits their messages; the broadcast channel is
chat:context:1, never empty.

GET /_bm/api/v1/chat answers the caller's membership behind jwt.auth and
the per-user bucket jz.bm.chat (240 a minute). The chat config block
(group, moderator_group, max_upload_bytes, max_embeds) is added. jz.bm
still Requires only golem15.user; all chat wiring is gated by HasPlugin.
2026-10-26 15:40:44 +01:00
67806f49a7 build: frontend with the owned-only readings filter 2026-10-26 11:19:22 +01:00
b4abf2630a build: frontend with the owned checkbox on readings 2026-10-26 11:12:08 +01:00
cf84f1d0e8 feat: per-student owned flag on readings
- new table jz_bm_reading_ownership and its migration
  20261026120000_create_jz_bm_reading_ownership
- PUT and DELETE /_bm/api/v1/readings/{id}/owned, idempotent
- owned_at on every reading in /readings and /courses/{id}
- read semantics, progress routes and counts unchanged
2026-10-26 11:11:22 +01:00
Jakub Zych
85cae45cb9 build: frontend with Microsoft 365 sign-in
The student app's login page offers Microsoft 365 when the provider is
configured, /auth/oauth/callback redeems the one-time code, a consent
screen finishes a first sign-in, the profile attaches Microsoft through
a link ticket, and the service worker leaves /oauth alone. The build
also carries the summer presentation theme already committed in the
frontend sources.
2026-10-21 00:23:38 +02:00
Jakub Zych
438c0b9761 fix: reserve /oauth for social sign-in
The SPA fallback no longer answers /oauth and the paths below it with
index.html, so golem15.sociallogin's start and provider callback routes
reach the backend; /oauthy is still a client route.
2026-10-21 00:15:31 +02:00
Jakub Zych
2536bcb959 Management API: record routes for courses, meetings, class sessions, readings and deadlines (Fillable + Rules + TemporalErrors, PATCH, filters) 2026-10-17 18:05:39 +02:00
Jakub Zych
996b4d1542 Management API: POST/DELETE /materials/{id}/files (attach.Store, 50 MB, 20 files), DELETE /materials/{id} removes files; download keeps the file name 2026-10-17 17:53:22 +02:00
Jakub Zych
584d15257c Sylabusy: PDF-y w public/sylabusy, typ application/pdf w serwerze statycznym 2026-10-17 12:06:24 +02:00
Jakub Zych
76f559b6d9 build: rebuild the student app (multi-line course descriptions) 2026-10-17 12:01:15 +02:00
Jakub Zych
ebd9117f8c feat: lecturer on class sessions and in the session course ref
The schedule showed a lecturer only where the session notes named one
(Globalizacja), so the student plan had nobody under the other courses.
The session JSON now carries the course lecturer in its course ref and an
optional per-session lecturer (new nullable column, admin field, seed key)
for courses shared between two people. The student app shows the
session's own lecturer or, failing that, the course's.
2026-10-17 11:20:11 +02:00
Jakub Zych
d2096e2128 feat(manage): GET and PUT /api/v1/bm/materials/{id}
The management API could only upsert a material on its title and course,
so a renamed note became a second material. PUT /materials/{id} applies the
same body to one material (422 when the new title and course belong to
another one), GET /materials/{id} shows a draft or published material with
its public files, and the upsert, update and validation share one path.
The README documents the management API.
2026-10-16 20:40:47 +02:00
Jakub Zych
2a8cdac282 public: slide counter in the public deck toolbar 2026-10-16 00:44:06 +02:00
Jakub Zych
b32668029c build: rebuild the student app (deadline card padding) 2026-10-15 23:23:16 +02:00
Jakub Zych
67e04b3101 build: rebuild the student app (deck themes, scheme switch) 2026-10-13 10:18:10 +02:00
Jakub Zych
b86cbbcd2d build: rebuild the student app (pwa) 2026-10-09 02:47:29 +02:00
Jakub Zych
a406a514d3 build: rebuild the student app (title-slide notes, pilot key order) 2026-10-09 02:31:53 +02:00
Jakub Zych
9aa620f975 build: rebuild the student app (phone remote review fixes) 2026-10-08 18:53:25 +02:00
Jakub Zych
5563e080cf fix: stop throttling the realtime subscribe proxy
Centrifugo calls the proxy from 127.0.0.1 for every client, so the
per-IP fallback put every subscribe into one bucket that any token
holder could exhaust. Throttle only the token route, per user.
2026-10-08 18:47:20 +02:00
Jakub Zych
2365bf6df9 build: rebuild the student app (phone remote layout) 2026-10-08 18:26:12 +02:00
Jakub Zych
e0a60e0f35 build: rebuild the student app (phone remote) 2026-10-08 18:14:15 +02:00
Jakub Zych
a740373b0e feat: wire the lighthouse realtime service
- Boot builds the realtime service and installs the user lookup
- the Centrifugo driver ships with the app; config keeps the null driver
- token and subscribe-proxy routes mount only with golem15.presentations,
  the token route behind presentations.realtime-owner
- jz.bm.realtime per-user throttle bucket and websockets:health
2026-10-08 17:53:54 +02:00
Jakub Zych
4b36eb940d build: rebuild the student app (speaker clock fix) 2026-10-08 14:01:00 +02:00
Jakub Zych
977b380f70 fix: stop prev-slide focus outline from slicing the deck 2026-10-06 23:45:21 +02:00
Jakub Zych
904c7b07d5 fix: pin dark lecture tokens in the deck viewer 2026-10-06 23:37:15 +02:00
Jakub Zych
8aefdab027 fix: follow system dark scheme in the deck viewer 2026-10-06 23:29:46 +02:00
Jakub Zych
30c424c814 build: rebuild presentation viewer 2026-10-06 22:42:04 +02:00
Jakub Zych
3f4829a6f2 feat(02-03): bundle the speaker clock and images
- Private toolbar and clock stay in the speaker chunk
- Speaker image fetches are not part of the public view
2026-10-06 19:36:03 +02:00
Jakub Zych
febf74c6c9 feat(02-03): bundle the owner list and speaker route
- The shell includes Moje prezentacje and the bare speaker tab
- Speaker copy stays in its own chunk, off the public deck
2026-10-06 19:20:10 +02:00
Jakub Zych
2eb9dfccd2 feat(02-02): bundle the public toolbar and reading layout
- rebuild the visitor assets with local fonts
- drop the previous hashed bundles replaced by this build
2026-10-06 18:46:46 +02:00
Jakub Zych
913fddb36b feat(02-02): bundle the public deck without external fonts
- Rebuild the embedded student app with self-hosted font files
- Drop the previous hashed assets replaced by this build
2026-10-06 18:35:49 +02:00
Jakub Zych
30df20c48d feat(02-01): gate the public presentation path
- 404 /_presentations before the SPA shell
- serve /prezentacje/{slugHash} only when presentations is active
- rebuild the embedded student app
2026-10-06 18:14:24 +02:00
Jakub Zych
9986df32a4 test(02-01): add failing test for the presentations prefix
- /_presentations must be a plain 404, not the SPA shell
- A router without the presentations plugin has no public document route
2026-10-06 18:05:09 +02:00