"""Tournament team-role sync for the economy/community guild. The tournament participants live in the *economy* (community) guild, not the internal dev guild, so team-role assignment runs here rather than as part of the member-roster sync in :mod:`commands.dev_member_commands`. This is deliberately roster-INDEPENDENT: it matches Discord usernames straight against the separate registration spreadsheet (``TEAM_SHEET_ID``) and never touches the member sheet. """ from __future__ import annotations import logging import discord from discord import app_commands from core import sheets from core.admin import bot_admin_check from core.member_sync import sync_all_team_roles import strings as S def register_economy_team_commands( tree: app_commands.CommandTree, bot: discord.Client, log: logging.Logger, ) -> None: @tree.command(name="teamsync", description=S.CMD["teamsync"]) @app_commands.guild_only() @bot_admin_check() async def cmd_teamsync(interaction: discord.Interaction): await interaction.response.defer(ephemeral=True) guild = interaction.guild if guild is None: await interaction.followup.send(S.ERR["guild_only"], ephemeral=True) return try: rosters = await sheets.refresh_teams() except Exception as e: await interaction.followup.send( S.TEAMSYNC_UI["refresh_error"].format(error=e), ephemeral=True ) return if not rosters: await interaction.followup.send(S.TEAMSYNC_UI["disabled"], ephemeral=True) return summary = await sync_all_team_roles(guild, log) await interaction.followup.send(_format_summary(summary), ephemeral=True) log.info( "/teamsync - scanned=%d, assigned=%d, removed=%d, created=%d, errors=%d", summary.scanned, summary.assigned, summary.removed, len(summary.created), len(summary.errors), ) def _format_summary(summary) -> str: lines = [ S.TEAMSYNC_UI["done"], S.TEAMSYNC_UI["scanned"].format(count=summary.scanned), S.TEAMSYNC_UI["assigned"].format(count=summary.assigned), S.TEAMSYNC_UI["removed"].format(count=summary.removed), ] if summary.created: # A team can be created only once, but the same role could surface for # several members in one run - de-dupe for the report. unique = list(dict.fromkeys(summary.created)) lines.append(S.TEAMSYNC_UI["created"].format(roles=", ".join(unique))) if summary.errors: lines.append(S.TEAMSYNC_UI["errors"].format(count=len(summary.errors))) text = "\n".join(lines) if summary.changes: shown = summary.changes[:20] text += "\n\n" + S.TEAMSYNC_UI["changes_header"] + "\n" + "\n".join(shown) if len(summary.changes) > 20: text += "\n" + S.TEAMSYNC_UI["changes_more"].format(count=len(summary.changes) - 20) else: text += "\n\n" + S.TEAMSYNC_UI["no_changes"] return text