feat: management polish, !cancel, !wordlestats, welcome fixes
- Add !cancel command (anyone cancels own blackjack; PL50+ clears all room games) - Add !wordlestats top-level command (wraps wordle stats function) - Add !cleanwelcome admin command to purge stale welcome DM records - !help now hides management section from sub-PL50 users, hides !health from non-admins - !announce uses nio room cache for join_rule instead of an API call per room - Fix _INVITEALL_BLOCKED comment (Commands is knock-gated, not restricted) - welcome.py: skip duplicate DM if a pending welcome already exists for the user - welcome.py: add clean_stale_dm_messages() helper - welcome.py: replace no-op post_welcome_message with log_ready() - bot.py: update import/call to match welcome.py rename Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+30
-10
@@ -19,11 +19,15 @@ logger = logging.getLogger("matrixbot")
|
||||
# The Space room to watch for new members
|
||||
SPACE_ROOM_ID = "!-1ZBnAH-JiCOV8MGSKN77zDGTuI3pgSdy8Unu_DrDyc"
|
||||
|
||||
# Public channels to invite new members to (skip Management + Cool Kids)
|
||||
# Public channels to invite new members to.
|
||||
# Intentionally excludes: Management, Cool Kids, Spam and Stuff (invite-only),
|
||||
# and Commands (knock-gated — access granted deliberately by admins).
|
||||
INVITE_ROOMS = [
|
||||
"!wfokQ1-pE896scu_AOcCBA2s3L4qFo-PTBAFTd0WMI0", # General (v12)
|
||||
"!ou56mVZQ8ZB7AhDYPmBV5_BR28WMZ4x5zwZkPCqjq1s", # Commands (v12)
|
||||
"!GK6v5cLEEnowIooQJv5jECfISUjADjt8aKhWv9VbG5U", # Memes (v12)
|
||||
"!wfokQ1-pE896scu_AOcCBA2s3L4qFo-PTBAFTd0WMI0", # General
|
||||
"!GK6v5cLEEnowIooQJv5jECfISUjADjt8aKhWv9VbG5U", # Memes
|
||||
"!ktQu0gavhjpCMkgxk8SYdb6mnJRY-u7mY7_KfksV0SU", # Music
|
||||
"!ARbRFSPNp2U0MslWTBGoTT3gbmJJ25dPRL6enQntvPo", # Voice
|
||||
"!3gMjTHqV-r823ZrvXnck7waB0Pd8tiCu-zbF7mSS83E", # Voice 2
|
||||
]
|
||||
|
||||
WELCOME_EMOJI = "\u2705" # checkmark
|
||||
@@ -49,6 +53,17 @@ def _save_state(state: dict):
|
||||
logger.error("Failed to save welcome state: %s", e)
|
||||
|
||||
|
||||
def clean_stale_dm_messages() -> int:
|
||||
"""Remove all pending welcome DM records. Returns count removed."""
|
||||
state = _load_state()
|
||||
pending = state.get("dm_welcome_messages", {})
|
||||
count = len(pending)
|
||||
if count:
|
||||
state["dm_welcome_messages"] = {}
|
||||
_save_state(state)
|
||||
return count
|
||||
|
||||
|
||||
async def handle_space_join(client: AsyncClient, sender: str):
|
||||
"""Called when a new user joins the Space. DM them a welcome message."""
|
||||
state = _load_state()
|
||||
@@ -57,6 +72,12 @@ async def handle_space_join(client: AsyncClient, sender: str):
|
||||
if sender in welcomed:
|
||||
return
|
||||
|
||||
# Skip if we already sent them a DM they haven't reacted to yet
|
||||
pending = state.get("dm_welcome_messages", {})
|
||||
if any(v["user"] == sender for v in pending.values()):
|
||||
logger.debug("Already have a pending welcome DM for %s, skipping", sender)
|
||||
return
|
||||
|
||||
logger.info("New Space member %s — sending welcome DM", sender)
|
||||
|
||||
dm_room = await get_or_create_dm(client, sender)
|
||||
@@ -66,13 +87,13 @@ async def handle_space_join(client: AsyncClient, sender: str):
|
||||
|
||||
plain = (
|
||||
"Welcome to The Lotus Guild!\n\n"
|
||||
f"React to this message with {WELCOME_EMOJI} to get invited to all channels.\n\n"
|
||||
"You'll be added to General, Commands, and Memes."
|
||||
f"React to this message with {WELCOME_EMOJI} to get invited to all public channels.\n\n"
|
||||
"You'll be added to General, Memes, Music, and the Voice channels."
|
||||
)
|
||||
html = (
|
||||
"<h3>Welcome to The Lotus Guild!</h3>"
|
||||
f"<p>React to this message with {WELCOME_EMOJI} to get invited to all channels.</p>"
|
||||
"<p>You'll be added to <b>General</b>, <b>Commands</b>, and <b>Memes</b>.</p>"
|
||||
f"<p>React to this message with {WELCOME_EMOJI} to get invited to all public channels.</p>"
|
||||
"<p>You'll be added to <b>General</b>, <b>Memes</b>, <b>Music</b>, and the <b>Voice</b> channels.</p>"
|
||||
)
|
||||
|
||||
resp = await send_html(client, dm_room, plain, html)
|
||||
@@ -145,6 +166,5 @@ async def handle_welcome_reaction(
|
||||
await send_text(client, room_id, "You're already in all the channels!")
|
||||
|
||||
|
||||
async def post_welcome_message(client: AsyncClient):
|
||||
"""No-op kept for backward compatibility with bot.py startup."""
|
||||
def log_ready():
|
||||
logger.info("Welcome module ready — watching Space for new members")
|
||||
|
||||
Reference in New Issue
Block a user