diff --git a/BOT/botscript.py b/BOT/botscript.py index d20c413..6c5cb39 100644 --- a/BOT/botscript.py +++ b/BOT/botscript.py @@ -990,6 +990,55 @@ async def test_weekly_br_error(interaction, error): await permission_fail(interaction, error) +@is_blacklisted() +@bot.tree.command( + name="resend-weekly-br", + description="[DEV] Force-resend the most recently ended Weekly BR Report to all configured channels", +) +async def resend_weekly_br(interaction: discord.Interaction): + """Clears the idempotency marker and re-dispatches the last BR window.""" + from .task_executors import execute_weekly_br_report_task, WEEKLY_BR_MARKER_PATH + + await collect_command_stats(interaction) + if not await is_dev_team(interaction): + await interaction.response.send_message(t("en", "dev.restricted_dev_team"), ephemeral=True) + return + + await interaction.response.defer(ephemeral=True) + + window = _pick_test_br_window() + if window is None: + await interaction.followup.send("Could not pick a BR window from SCHEDULE.json.", ephemeral=True) + return + + # Clear the idempotency marker so execute_weekly_br_report_task will proceed. + try: + WEEKLY_BR_MARKER_PATH.unlink(missing_ok=True) + except Exception as e: + await interaction.followup.send(f"Failed to clear marker file: {e}", ephemeral=True) + return + + start_ts = int(window["start"]) + end_ts = int(window["end"]) + await interaction.followup.send( + f"Resending **{window['max_br']} BR** window " + f"() to all configured channels…", + ephemeral=True, + ) + + try: + await execute_weekly_br_report_task(window) + await interaction.followup.send("✅ Resend complete.", ephemeral=True) + except Exception as e: + logging.error("[RESEND-WBR] Error: %s", e) + await interaction.followup.send(f"❌ Resend failed: {e}", ephemeral=True) + + +@resend_weekly_br.error +async def resend_weekly_br_error(interaction, error): + logging.error("[RESEND-WBR] Unhandled error: %s", error) + + async def _diagnose_perms_logic(interaction: discord.Interaction, target_channel=None): """Core logic for autolog diagnostics. Called from the diagnose channel select.""" await interaction.response.defer(ephemeral=True) diff --git a/BOT/task_executors.py b/BOT/task_executors.py index 4680225..a61f47d 100644 --- a/BOT/task_executors.py +++ b/BOT/task_executors.py @@ -2039,13 +2039,8 @@ async def execute_weekly_br_report_task(window: Dict[str, Any]) -> None: if wildcard_channel_id is None and not squadron_channels: continue - # Dedupe: drop per-squadron entries that target the same channel as wildcard. - if wildcard_channel_id is not None: - squadron_channels = [ - (cid, pref_key, info) - for cid, pref_key, info in squadron_channels - if cid != wildcard_channel_id - ] + # Per-squadron reports are distinct from the wildcard report and may + # legitimately share the same channel — both should be sent. # Resolve guild language once per guild guild_features = await load_features(guild_id)