forked from sass/tipibot
feat(teams): add opt-in /teamsync reposition to tidy existing team roles
Creation-time placement only positions NEW team roles. Team roles made before divider placement existed (sitting at the bottom of the role list) stayed put. Add `reposition_team_roles(guild)` and expose it via `/teamsync reposition:true` (off by default, so the hourly task never reorders roles on its own). It moves each EXISTING team role under its game's divider, sheet-driven: - a role's game/divider comes from sheets.get_game_for_team; - roles whose team is no longer in the sheet (or game unknown) are left alone; - idempotent: a role already within its section band (below its own divider, above the next divider down) is skipped, so re-runs move nothing. Adds RepositionSummary, TEAMSYNC_UI/OPT strings, and tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R6JZkyszyDFuFtk25WBbcR
This commit is contained in:
@@ -16,7 +16,7 @@ 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
|
||||
from core.member_sync import reposition_team_roles, sync_all_team_roles
|
||||
import strings as S
|
||||
|
||||
|
||||
@@ -27,8 +27,9 @@ def register_economy_team_commands(
|
||||
) -> None:
|
||||
@tree.command(name="teamsync", description=S.CMD["teamsync"])
|
||||
@app_commands.guild_only()
|
||||
@app_commands.describe(reposition=S.OPT["teamsync_reposition"])
|
||||
@bot_admin_check()
|
||||
async def cmd_teamsync(interaction: discord.Interaction):
|
||||
async def cmd_teamsync(interaction: discord.Interaction, reposition: bool = False):
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
|
||||
guild = interaction.guild
|
||||
@@ -48,14 +49,22 @@ def register_economy_team_commands(
|
||||
return
|
||||
|
||||
summary = await sync_all_team_roles(guild, log)
|
||||
await interaction.followup.send(_format_summary(summary), ephemeral=True)
|
||||
message = _format_summary(summary)
|
||||
|
||||
repo = None
|
||||
if reposition:
|
||||
repo = await reposition_team_roles(guild, log)
|
||||
message += "\n\n" + _format_reposition(repo)
|
||||
|
||||
await interaction.followup.send(message, ephemeral=True)
|
||||
log.info(
|
||||
"/teamsync - scanned=%d, assigned=%d, removed=%d, created=%d, errors=%d",
|
||||
"/teamsync - scanned=%d, assigned=%d, removed=%d, created=%d, errors=%d%s",
|
||||
summary.scanned,
|
||||
summary.assigned,
|
||||
summary.removed,
|
||||
len(summary.created),
|
||||
len(summary.errors),
|
||||
f", repositioned={repo.moved}" if repo else "",
|
||||
)
|
||||
|
||||
|
||||
@@ -85,3 +94,17 @@ def _format_summary(summary) -> str:
|
||||
text += "\n\n" + S.TEAMSYNC_UI["no_changes"]
|
||||
|
||||
return text
|
||||
|
||||
|
||||
def _format_reposition(repo) -> str:
|
||||
lines = [S.TEAMSYNC_UI["reposition_header"]]
|
||||
if not repo.moved:
|
||||
lines.append(S.TEAMSYNC_UI["reposition_none"])
|
||||
else:
|
||||
lines.append(S.TEAMSYNC_UI["repositioned"].format(count=repo.moved))
|
||||
lines.extend(repo.moves[:20])
|
||||
if len(repo.moves) > 20:
|
||||
lines.append(S.TEAMSYNC_UI["changes_more"].format(count=len(repo.moves) - 20))
|
||||
if repo.errors:
|
||||
lines.append(S.TEAMSYNC_UI["errors"].format(count=len(repo.errors)))
|
||||
return "\n".join(lines)
|
||||
|
||||
Reference in New Issue
Block a user