Node page Discord picker: org's servers + voice channels, not raw IDs (#213 item 3) #220

Merged
logan merged 4 commits from feat/213-node-join-picker into main 2026-10-04 22:05:50 -04:00
3 changed files with 21 additions and 9 deletions
Showing only changes of commit a2c840f186 - Show all commits
+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):
+2 -2
View File
@@ -134,8 +134,8 @@ function DiscordPicker({
<legend className="text-xs text-ink-muted mb-2">Discord server</legend>
{usable.length === 0 ? (
<p className="text-xs text-ink-2 bg-raised border border-line rounded-lg px-3 py-2">
No Discord server is linked to your organization yet. Add the DRB bot to your server; a platform
admin then links it to your organization.
No Discord server is linked to your organization yet. Add the DRB bot to your Discord server and
link it to your organization; it shows up here once the bot reports its channels.
</p>
) : (
<div className="space-y-1.5">