Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions tests/test_admin_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,16 @@ def admin_cog(self, mock_bot, database):

@pytest.mark.asyncio
async def test_admin_panel_opens_unified_view(self, admin_cog, mock_interaction_admin):
await admin_cog.db.upsert_guild_config("111111", "987654", "123456")
member = mock_interaction_admin.guild.get_member(mock_interaction_admin.user.id)
member.roles = [MockRole("League Admin", role_id=987654)]

await admin_cog.panel.callback(admin_cog, mock_interaction_admin)

assert isinstance(mock_interaction_admin.response_sent[0]["view"], UnifiedAdminPanelView)
content = mock_interaction_admin.response_sent[0]["content"]
assert "Admin role: <@&987654>" in content
assert "League channel: <#123456>" in content

def test_admin_group_exposes_panel_command(self, admin_cog):
assert any(command.name == "panel" for command in admin_cog.admin.commands)
Expand Down Expand Up @@ -165,6 +172,11 @@ async def test_inline_setup_button_opens_selector_view(
await setup_button.callback(mock_interaction_admin)

assert isinstance(mock_interaction_admin.response_sent[-1]["view"], GuildSetupPromptView)
assert "this server's league" in mock_interaction_admin.response_sent[-1]["content"]
assert (
"Fixtures, reminders, results, and standings"
in mock_interaction_admin.response_sent[-1]["content"]
)

@pytest.mark.asyncio
async def test_configured_panel_setup_button_opens_reconfigure_flow(
Expand All @@ -183,6 +195,9 @@ async def test_configured_panel_setup_button_opens_reconfigure_flow(
await setup_button.callback(mock_interaction_admin)

assert isinstance(mock_interaction_admin.response_sent[-1]["view"], GuildSetupPromptView)
assert (
"admin role and league channel" in mock_interaction_admin.response_sent[-1]["content"]
)

@pytest.mark.asyncio
async def test_inline_setup_button_blocks_owner_without_setup_permission(
Expand All @@ -200,6 +215,9 @@ async def test_inline_setup_button_blocks_owner_without_setup_permission(
await setup_button.callback(mock_interaction_admin)

assert mock_interaction_admin.response_sent[-1].get("view") is None
assert (
"Administrator or Manage Server" in mock_interaction_admin.response_sent[-1]["content"]
)

@pytest.mark.asyncio
async def test_inline_setup_selector_rechecks_setup_permission(
Expand Down Expand Up @@ -234,6 +252,7 @@ async def test_inline_setup_prompt_saves_config(
config = await database.get_guild_config("111111")
assert config["admin_role_id"] == "987654"
assert config["league_channel_id"] == "765432"
assert "this server's league" in mock_interaction_admin.response_sent[-1]["content"]

@pytest.mark.asyncio
async def test_inline_setup_prompt_requires_confirmation_for_everyone_role(
Expand Down
30 changes: 19 additions & 11 deletions typer_bot/commands/admin_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,21 @@ async def _save_guild_config(


def _setup_saved_message(admin_role: discord.Role, league_channel: discord.TextChannel) -> str:
return f"TyperBot setup saved. Admin role: {admin_role.mention}. League channel: {league_channel.mention}."
return (
"TyperBot setup saved for this server's league. "
f"Admin role: {admin_role.mention}. League channel: {league_channel.mention}."
)


def _setup_permission_message() -> str:
return "Only someone with Administrator or Manage Server can configure TyperBot."


def _setup_prompt_message() -> str:
return (
"Choose the TyperBot admin role and league channel for this server's league. "
"Fixtures, reminders, results, and standings will be posted there."
)


class EveryoneRoleConfirmView(discord.ui.View):
Expand All @@ -78,9 +92,7 @@ async def interaction_check(self, interaction: discord.Interaction) -> bool:
)
return False
if not has_setup_permission(interaction):
await interaction.response.send_message(
"Only a server admin can configure TyperBot for this server.", ephemeral=True
)
await interaction.response.send_message(_setup_permission_message(), ephemeral=True)
return False
return True

Expand Down Expand Up @@ -191,9 +203,7 @@ async def interaction_check(self, interaction: discord.Interaction) -> bool:
)
return False
if not has_setup_permission(interaction):
await interaction.response.send_message(
"Only a server admin can configure TyperBot for this server.", ephemeral=True
)
await interaction.response.send_message(_setup_permission_message(), ephemeral=True)
return False
return True

Expand All @@ -208,13 +218,11 @@ def __init__(self, parent_view: GuildSetupStartView):

async def callback(self, interaction: discord.Interaction):
if not has_setup_permission(interaction):
await interaction.response.send_message(
"Only a server admin can configure TyperBot for this server.", ephemeral=True
)
await interaction.response.send_message(_setup_permission_message(), ephemeral=True)
return

await interaction.response.edit_message(
content="Choose the TyperBot admin role and league channel below.",
content=_setup_prompt_message(),
view=GuildSetupPromptView(self.parent_view.db, str(interaction.user.id)),
)

Expand Down
5 changes: 5 additions & 0 deletions typer_bot/commands/admin_panel/unified.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def __init__(
self.active_season_has_scores = False
self.current_prediction: dict | None = None
self.active_season: dict | None = None
self.guild_config: dict | None = None
self.fixture_select = FixtureSelect(self)
self.user_select = PredictionUserSelect(self)
self.user_select.update_options([])
Expand Down Expand Up @@ -152,6 +153,7 @@ def _refresh_items(self) -> None:
self.add_item(SetupBotButton(self, row=4))

async def load_fixture_options(self) -> None:
self.guild_config = await self.db.get_guild_config(self.guild_id)
self.active_season = await self.db.get_or_create_active_season(self.guild_id)
self.active_season_has_scores = await self.db.active_season_has_scores(self.guild_id)
fixtures = await self.db.get_recent_fixtures(self.guild_id, MAX_SELECT_OPTIONS)
Expand Down Expand Up @@ -197,6 +199,9 @@ async def populate_fixture_details(self, fixture: dict | None) -> None:

def render_content(self) -> str:
lines = ["**Admin Panel**"]
if self.guild_config is not None:
lines.append(f"Admin role: <@&{self.guild_config['admin_role_id']}>")
lines.append(f"League channel: <#{self.guild_config['league_channel_id']}>")
if self.active_season is not None:
lines.append(f"Active season: {self.active_season['name']}")
lines.append(_format_scoring_rules(self.active_season["scoring_rules"]))
Expand Down
5 changes: 3 additions & 2 deletions typer_bot/commands/admin_panel/unified_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ async def callback(self, interaction: discord.Interaction):

if not has_setup_permission(interaction):
await interaction.response.send_message(
"Only a server admin can configure TyperBot for this server.", ephemeral=True
"Only someone with Administrator or Manage Server can configure TyperBot.",
ephemeral=True,
)
return

await interaction.response.send_message(
"Update TyperBot setup for this server.",
"Update the admin role and league channel for this server's league.",
view=GuildSetupPromptView(self.parent_view.db, str(interaction.user.id)),
ephemeral=True,
)
Expand Down
Loading