Add !rooms over <term> search: filter rooms by name/alias/topic (case-insensitive, all terms must match); v2.4.0

This commit is contained in:
Eddy de Vink 2026-09-06 14:34:04 +02:00
commit d6c9fd8004
3 changed files with 80 additions and 21 deletions

View file

@ -1,6 +1,6 @@
maubot: 0.1.0
id: nl.roomsoverview
version: 2.3.1
version: 2.4.0
license: MIT
modules:
- roomsoverview

Binary file not shown.

View file

@ -435,23 +435,16 @@ class RoomsOverviewPlugin(Plugin):
)
return [dict(r) for r in rows]
async def _send_list(self, evt: MessageEvent) -> None:
rooms = await self._list_rooms()
if not rooms:
await evt.reply(
"De room-index is nog leeg. Moderators kunnen rooms toevoegen met "
"`!rooms add <room-id-of-alias>`."
)
return
def _sort_rooms(self, rooms: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
return sorted(
rooms,
key=lambda r: (
r.get("display_name") or r.get("canonical_alias") or r["room_id"]
).lower(),
)
def sort_key(r: Dict[str, Any]) -> str:
return (
r.get("display_name")
or r.get("canonical_alias")
or r["room_id"]
).lower()
rooms.sort(key=sort_key)
def _build_cards(self, rooms: List[Dict[str, Any]]) -> List[Tuple[str, str]]:
"""Bouw per room een blockquote-kaart (html, plain)."""
# Elke room wordt een blockquote-kaart: icoontje + naam/leden als kop,
# omschrijving eronder, onderaan de join-link. De formatted_body bouwen
@ -510,13 +503,21 @@ class RoomsOverviewPlugin(Plugin):
f"{e(address)}</a></p></blockquote>"
)
cards.append(("".join(body_parts), plain))
return cards
async def _send_cards(
self,
evt: MessageEvent,
cards: List[Tuple[str, str]],
subject: str,
count_label: str,
) -> None:
chunk_size = max(1, int(self.config.get("rooms_per_message", 50) or 50))
chunks = [cards[i : i + chunk_size] for i in range(0, len(cards), chunk_size)]
total = len(cards)
for idx, chunk in enumerate(chunks, start=1):
header = f"Rooms overzicht ({total} rooms getoond, deel {idx}/{len(chunks)}):"
header = f"{subject} ({total} {count_label}, deel {idx}/{len(chunks)}):"
html_body = (
f'<p><b>{html.escape(header)}</b></p>'
+ "".join(html_part for html_part, _ in chunk)
@ -530,6 +531,47 @@ class RoomsOverviewPlugin(Plugin):
)
await evt.respond(content)
async def _send_list(self, evt: MessageEvent) -> None:
rooms = self._sort_rooms(await self._list_rooms())
if not rooms:
await evt.reply(
"De room-index is nog leeg. Moderators kunnen rooms toevoegen met "
"`!rooms add <room-id-of-alias>`."
)
return
await self._send_cards(
evt, self._build_cards(rooms), "Rooms overzicht", "rooms getoond"
)
async def _search_rooms(self, terms: str) -> List[Dict[str, Any]]:
"""Zoek rooms: alle termen moeten matchen (case-insensitive, substring)
in naam, alias of omschrijving."""
needles = [t for t in (part.lower() for part in terms.split()) if t]
if not needles:
return []
found = []
for r in await self._list_rooms():
hay = " ".join(
str(r.get(field) or "").lower()
for field in ("display_name", "canonical_alias", "topic")
)
if all(n in hay for n in needles):
found.append(r)
return self._sort_rooms(found)
async def _send_search(self, evt: MessageEvent, query: str) -> None:
found = await self._search_rooms(query)
query_label = " ".join(query.split())
if not found:
await evt.reply(f"Geen rooms gevonden voor `{query_label}`.")
return
await self._send_cards(
evt,
self._build_cards(found),
f"Zoekresultaten voor '{query_label}'",
"gevonden",
)
async def _send_help(self, evt: MessageEvent) -> None:
"""Uitgebreide Nederlandstalige handleiding voor !rooms."""
help_text = (
@ -539,7 +581,10 @@ class RoomsOverviewPlugin(Plugin):
"naast de naam.\n\n"
"**Basis:**\n"
"* `!rooms` — toon de volledige lijst (bij veel rooms verdeeld "
"over meerdere berichten)\n\n"
"over meerdere berichten)\n"
"* `!rooms over <zoekterm ...>` — zoek rooms op naam, alias en/of "
"omschrijving (bijv. `!rooms over linux`); alle termen moeten "
"matchen\n\n"
"**Subcommando's (moderator of hoger vereist):**\n"
"* `!rooms add <room-id of #alias>` — voeg een room toe aan de index\n"
"* `!rooms edit <room-id of #alias> <veld>=<waarde>` — wijzig een "
@ -561,7 +606,7 @@ class RoomsOverviewPlugin(Plugin):
@command.new(
name="rooms",
help="Toon de room-index als kaarten; subcommands: add, edit, remove, refresh, help",
help="Toon de room-index als kaarten; subcommands: over (zoeken), add, edit, remove, refresh, help",
require_subcommand=False,
)
async def handle_rooms(self, evt: MessageEvent) -> None:
@ -572,6 +617,20 @@ class RoomsOverviewPlugin(Plugin):
async def rooms_help(self, evt: MessageEvent) -> None:
await self._send_help(evt)
@handle_rooms.subcommand(
name="over",
help="Zoek rooms op naam, alias of omschrijving: !rooms over <zoekterm ...>",
)
@command.argument("terms", pass_raw=True, required=True)
async def search_over(self, evt: MessageEvent, terms: str) -> None:
if not terms.strip():
await evt.reply(
"Gebruik: `!rooms over <zoekterm ...>` (bijv. `!rooms over linux`).\n"
"Zoekt op naam, alias en omschrijving; alle termen moeten matchen."
)
return
await self._send_search(evt, terms)
@handle_rooms.subcommand(
name="add",
help="Voeg een room toe aan de index: !rooms add <room-id of #alias> (moderator+)",