|
|
@@ -317,6 +317,9 @@ class ChattoAdapter(BasePlatformAdapter):
|
|
|
# only for [universal] tags in the joined-rooms log line, never for
|
|
|
# gating.
|
|
|
self._universal_room_ids: set[str] = set()
|
|
|
+ # DM room ID -> chat partner's login, resolved once via the member
|
|
|
+ # directory so the joined-rooms summary can name who a DM is with.
|
|
|
+ self._dm_partners: dict[str, str] = {}
|
|
|
# One-shot guard for the unjoined-home-channel warning in _refresh_rooms.
|
|
|
self._home_warning_logged = False
|
|
|
self._ws_task: asyncio.Task | None = None
|
|
|
@@ -1596,16 +1599,42 @@ class ChattoAdapter(BasePlatformAdapter):
|
|
|
home_id,
|
|
|
)
|
|
|
|
|
|
+ async def _resolve_dm_partner(self, client: ChattoClient, room_id: str) -> None:
|
|
|
+ """Cache the chat partner's login for a DM room, best-effort.
|
|
|
+
|
|
|
+ DM rooms carry no usable name of their own, so the joined-rooms
|
|
|
+ summary names the other side instead. Resolved once per room and
|
|
|
+ session; without our own user (pre-connect) or on a directory error
|
|
|
+ the raw room name stays in place.
|
|
|
+ """
|
|
|
+ if room_id in self._dm_partners or self.me is None:
|
|
|
+ return
|
|
|
+ try:
|
|
|
+ members, _page = await client.list_room_members(room_id)
|
|
|
+ except Exception:
|
|
|
+ logger.debug(
|
|
|
+ "Chatto: could not list members of DM %s", room_id, exc_info=True
|
|
|
+ )
|
|
|
+ return
|
|
|
+ for member in members:
|
|
|
+ user = member.user
|
|
|
+ if user and user.id != self.me.id:
|
|
|
+ self._dm_partners[room_id] = user.login or user.display_name
|
|
|
+ return
|
|
|
+
|
|
|
def _joined_room_label(self, room_id: str) -> str:
|
|
|
"""One entry for the joined-rooms summary, with how-we-answer tags.
|
|
|
|
|
|
The tag names the room's participation mode at a glance: DMs answer
|
|
|
unconditionally, listed channels answer on mentions or every message,
|
|
|
- and an unlisted channel is read-only.
|
|
|
+ and an unlisted channel is read-only. A DM is labelled with its chat
|
|
|
+ partner's login rather than its (empty) room name, and names are
|
|
|
+ quoted so empty strings and spaces stay visible.
|
|
|
"""
|
|
|
name = self._room_names.get(room_id, room_id)
|
|
|
if self._room_kinds.get(room_id) == RoomKind.DM:
|
|
|
tags = "[dm]"
|
|
|
+ name = self._dm_partners.get(room_id) or name
|
|
|
else:
|
|
|
policy = self._room_policy(room_id)
|
|
|
if policy == RoomPolicy.REQUIRE_MENTION:
|
|
|
@@ -1616,7 +1645,7 @@ class ChattoAdapter(BasePlatformAdapter):
|
|
|
tags = "[read-only]"
|
|
|
if room_id in self._universal_room_ids:
|
|
|
tags += " [universal]"
|
|
|
- return f"{name} ({room_id}) {tags}"
|
|
|
+ return f'"{name}" ({room_id}) {tags}'
|
|
|
|
|
|
def _log_joined_rooms(self) -> None:
|
|
|
"""Log the joined rooms and how the bot answers in each of them."""
|
|
|
@@ -1649,6 +1678,8 @@ class ChattoAdapter(BasePlatformAdapter):
|
|
|
|
|
|
self._room_names[room_obj.id] = room_obj.name
|
|
|
self._room_kinds[room_obj.id] = room_obj.kind
|
|
|
+ if room_obj.kind == RoomKind.DM:
|
|
|
+ await self._resolve_dm_partner(client, room_obj.id)
|
|
|
if room_obj.universal:
|
|
|
self._universal_room_ids.add(room_obj.id)
|
|
|
|