From 8bcb7ff049536ffda347c9bbf561425ec2a375f1 Mon Sep 17 00:00:00 2001 From: Inferencebot Date: Mon, 2 Nov 2026 19:51:11 +0000 Subject: [PATCH] sync: invite members to configured MATRIX_INVITE_ROOMS (Skillshare) sync_matrix_space() now invites every active member to the rooms in member_invite_rooms(): MATRIX_INVITE_ROOMS when set, else the co-op Space + General room; legacy MATRIX_EXTRA_ROOMS is still appended. The set is explicit configuration, never "every child of the Space", so operator-only rooms are not pushed at members. Skillshare (!NSPfCdVP7TWTtFoAz1TxVOcqnoDIpMoJDiPb_XS79ys) was missing from the invite set, so no member who joined after it was created was ever told about it; including it here makes the nightly sweep self-heal. --- app/main.py | 52 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/app/main.py b/app/main.py index 61d6289..0a6221e 100644 --- a/app/main.py +++ b/app/main.py @@ -318,10 +318,16 @@ MATRIX_HOMESERVER = os.environ.get("MATRIX_HOMESERVER", "https://matrix.inferenc MATRIX_BOT_TOKEN = os.environ.get("MATRIX_BOT_TOKEN", "") MATRIX_SPACE_ID = os.environ.get("MATRIX_SPACE_ID", "") MATRIX_GENERAL_ROOM = os.environ.get("MATRIX_GENERAL_ROOM", "") -# Additional member-facing rooms that every member gets invited to (comma-separated -# room IDs). Restricted rooms are NOT discoverable over federation until a member -# has joined (the space hierarchy omits them for remote servers), so new rooms need -# an explicit invite pass — either here or a one-off script. +# The explicit set of rooms every active member is invited to (comma-separated +# room IDs). This is authoritative configuration and is deliberately NOT derived +# from the Space's children — some child rooms (operator/admin-only) must never +# be pushed at every member. When unset, sync_matrix_space() falls back to the +# co-op Space + General room. Restricted rooms are NOT discoverable over +# federation until a member has joined (the space hierarchy omits them for remote +# servers), so member-facing rooms need this explicit invite pass. +MATRIX_INVITE_ROOMS = [r.strip() for r in os.environ.get("MATRIX_INVITE_ROOMS", "").split(",") if r.strip()] +# Legacy alias kept for compatibility: extra member-facing rooms appended to the +# invite set above (superseded by MATRIX_INVITE_ROOMS). MATRIX_EXTRA_ROOMS = [r.strip() for r in os.environ.get("MATRIX_EXTRA_ROOMS", "").split(",") if r.strip()] LOOMIO_GROUP_ID = os.environ.get("LOOMIO_GROUP_ID", "") # Operator accounts that must always remain in the Loomio group (never removed @@ -1317,9 +1323,38 @@ async def loomio_fix_usernames(client: httpx.AsyncClient) -> dict: return {"fixed": fixed, "skipped": skipped} -async def sync_matrix_space() -> dict: - """Invite every active member to the co-op Matrix Space (and General room). +def member_invite_rooms() -> list[str]: + """The explicit set of rooms every active member of the co-op is invited to. + MATRIX_INVITE_ROOMS is authoritative when set; otherwise we fall back to the + co-op Space and General room. The legacy MATRIX_EXTRA_ROOMS entries are + appended (deduped) so existing configuration keeps working. This is + deliberately explicit configuration and never "every child of the Space": + operator/admin-only child rooms must not be pushed at every member. + """ + if MATRIX_INVITE_ROOMS: + rooms = list(MATRIX_INVITE_ROOMS) + else: + rooms = [MATRIX_SPACE_ID] + if MATRIX_GENERAL_ROOM: + rooms.append(MATRIX_GENERAL_ROOM) + for r in MATRIX_EXTRA_ROOMS: + if r and r not in rooms: + rooms.append(r) + seen: set[str] = set() + out: list[str] = [] + for r in rooms: + if r and r not in seen: + seen.add(r) + out.append(r) + return out + + +async def sync_matrix_space() -> dict: + """Invite every active member to the configured co-op Matrix rooms. + + The room set comes from member_invite_rooms(): MATRIX_INVITE_ROOMS when set, + else the co-op Space + General room, plus the legacy MATRIX_EXTRA_ROOMS. Members log in via Cloudron SSO, so their local MXID is @:inference.coop. We resolve the Cloudron username for each active member email and invite them if not already in the space. @@ -1371,10 +1406,7 @@ async def sync_matrix_space() -> dict: async for email, mxid in matrix_member_mxids(client): if not mxid or mxid in joined or mxid in invited: continue - await invite(mxid, MATRIX_SPACE_ID) - if MATRIX_GENERAL_ROOM: - await invite(mxid, MATRIX_GENERAL_ROOM) - for room in MATRIX_EXTRA_ROOMS: + for room in member_invite_rooms(): await invite(mxid, room) invited_count += 1 if invited_count: