Picker: share PR #218's guild_name field and its no-fallback-after-unlink rule

A server an org explicitly unlinked (unlinked_at) must not fall back to the
default org in the picker either, or the founding org could stream into it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Logan Cusano
2026-10-04 20:03:44 -04:00
co-authored by Claude Opus 5.5
parent 62e6d69bfa
commit a2c840f186
3 changed files with 21 additions and 9 deletions
+14 -6
View File
@@ -83,7 +83,8 @@ async def put_guild_directory(guild_id: str, body: GuildDirectory, _: dict = Dep
if body.present:
data["voice_channels"] = [c.model_dump() for c in body.voice_channels]
if body.name:
data["name"] = body.name
# Same field the /drb link flow writes (feat/213-guild-link, PR #218).
data["guild_name"] = body.name
await fstore.doc_set(streams.GUILDS, guild_id, data)
return {"ok": True, "guild_id": guild_id, "voice_channels": len(body.voice_channels)}
@@ -109,23 +110,30 @@ async def _node_for_caller(node_id: str, decoded: dict) -> tuple[dict, bool]:
return node, can
def _guild_name(g: dict) -> Optional[str]:
return g.get("guild_name") or g.get("name")
def _require_control(can: bool) -> None:
if not can:
raise HTTPException(403, "Only the organization owner, an admin, or this node's operator can do that.")
async def _org_guilds(org_id: str) -> list[dict]:
"""``discord_guilds`` docs this org may stream into, bot still present."""
"""``discord_guilds`` docs this org may stream into, bot still present.
Mirrors streams.resolve_guild_org: explicit link, else the unlinked-server
fallback org — except a server an org explicitly unlinked (``unlinked_at``,
PR #218), which gets no fallback."""
fallback = settings.discord_unlinked_guild_org_id or None
out = []
for g in await fstore.collection_list(streams.GUILDS):
gid = str(g.get("guild_id") or "")
if not gid or g.get("bot_present") is False:
continue
owner = g.get("org_id") or fallback
owner = g.get("org_id") or (None if g.get("unlinked_at") else fallback)
if owner and owner == org_id:
out.append(g)
out.sort(key=lambda g: ((g.get("name") or "").lower(), g["guild_id"]))
out.sort(key=lambda g: ((_guild_name(g) or "").lower(), g["guild_id"]))
return out
@@ -183,7 +191,7 @@ async def join_options(node_id: str, decoded: dict = Depends(require_firebase_to
})
out_guilds.append({
"guild_id": gid,
"name": g.get("name"),
"name": _guild_name(g),
"linked": bool(g.get("org_id")),
"synced": g.get("voice_channels") is not None,
"synced_at": g.get("directory_at"),
@@ -253,7 +261,7 @@ async def start_node_stream(node_id: str, body: NodeStreamStart, decoded: dict =
doc = await streams.start_stream(
org_id=org_id, guild_id=guild_id, channel_id=channel_id, system_id=system_id,
node_id=node_id, mode=body.mode,
channel_name=channel.get("name"), guild_name=guild.get("name"),
channel_name=channel.get("name"), guild_name=_guild_name(guild),
created_by=f"web:{decoded.get('uid') or 'unknown'}",
max_streams=settings.discord_guild_max_streams,
)
+5 -1
View File
@@ -74,7 +74,7 @@ def test_directory_push_keeps_org_link(fs):
run(web.put_guild_directory("100", body, {"service": True}))
g = fs.get("discord_guilds", "100")
assert g["org_id"] == ORG
assert g["name"] == "Fire Co. 7 (renamed)"
assert g["guild_name"] == "Fire Co. 7 (renamed)"
assert [c["channel_id"] for c in g["voice_channels"]] == ["1003"]
@@ -112,6 +112,10 @@ def test_options_unlinked_fallback_follows_bot_rule(fs, monkeypatch):
got = {g["guild_id"]: g for g in run(web.join_options("n1", OWNER))["guilds"]}
assert got["300"]["linked"] is False
assert "200" not in got
# An org that explicitly unlinked its server (PR #218) never falls back.
fs.put("discord_guilds", "300", {"guild_id": "300", "org_id": None, "unlinked_at": "2026-10-04T00:00:00+00:00",
"guild_name": "Unlinked", "voice_channels": []})
assert "300" not in [g["guild_id"] for g in run(web.join_options("n1", OWNER))["guilds"]]
def test_options_other_org_node_is_404(fs):