-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/capr 46 guild settings user experience improvement #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,6 +48,7 @@ def _ensure_settings(self, guild_id: int) -> GuildSettings: | |
| app_commands.Choice(name="announcement", value="announcement"), | ||
| app_commands.Choice(name="feedback", value="feedback"), | ||
| app_commands.Choice(name="onboarding", value="onboarding"), | ||
| app_commands.Choice(name="summary", value="summary"), | ||
| ] | ||
| ) | ||
| @app_commands.guild_only() | ||
|
|
@@ -69,6 +70,8 @@ async def guild(self, interaction: discord.Interaction, action: str) -> None: | |
| await self._open_feedback(interaction, settings) | ||
| elif action == "onboarding": | ||
| await self._open_onboarding(interaction, settings) | ||
| elif action == "summary": | ||
| await self._show_summary(interaction, settings) | ||
|
|
||
| # -- Modal launchers ----------------------------------------------------- | ||
|
|
||
|
|
@@ -89,7 +92,7 @@ async def _open_channels(self, interaction: discord.Interaction, settings: Guild | |
|
|
||
| async def _open_roles(self, interaction: discord.Interaction, settings: GuildSettings) -> None: | ||
| """Launch the role settings modal pre-filled with current values.""" | ||
| initial = {"admin": settings.admin_role, "member": settings.member_role} | ||
| initial = {"admin": settings.admin_role, "member": ", ".join(settings.member_roles)} | ||
| modal = ModelModal( | ||
| model_cls=RoleSettingsForm, callback=self._handle_roles, title="Role Settings", initial_data=initial | ||
| ) | ||
|
Comment on lines
+95
to
98
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (bug_risk): The role settings modal prefill suggests multiple member roles but the handler only persists a single value. Right now the modal shows a comma-separated list from |
||
|
|
@@ -149,7 +152,7 @@ async def _handle_roles(self, interaction: discord.Interaction, form: RoleSettin | |
| return | ||
| settings = self._ensure_settings(interaction.guild.id) | ||
| settings.admin_role = form.admin or None | ||
| settings.member_role = form.member or None | ||
| settings.member_roles = [form.member] if form.member else [] | ||
| await interaction.response.send_message("✅ Role settings saved.", ephemeral=True) | ||
|
|
||
| async def _handle_announcement(self, interaction: discord.Interaction, form: AnnouncementChannelForm) -> None: | ||
|
|
@@ -179,6 +182,89 @@ async def _handle_welcome(self, interaction: discord.Interaction, form: WelcomeM | |
| settings.onboarding_welcome = form.message or None | ||
| await interaction.response.send_message("✅ Welcome message updated.", ephemeral=True) | ||
|
|
||
| @app_commands.command(name="set_channel", description="Set a channel for a specific purpose") | ||
| @app_commands.describe(channel="The channel to set") | ||
| async def set_channel(self, interaction: discord.Interaction, channel: discord.TextChannel) -> None: | ||
| """Set a channel by mentioning it.""" | ||
| if not interaction.guild: | ||
| await interaction.response.send_message("This must be used in a server.", ephemeral=True) | ||
| return | ||
|
|
||
| settings = self._ensure_settings(interaction.guild.id) | ||
| settings.reports_channel = channel.id # Example: Assigning to reports_channel | ||
| await interaction.response.send_message(f"\u2705 Channel {channel.mention} has been set!", ephemeral=True) | ||
|
|
||
| @app_commands.command(name="set_role", description="Set a role for a specific purpose") | ||
| @app_commands.describe( | ||
| role_type="The type of role to set (admin or member)", | ||
| role="The role to set", | ||
| action="Action to perform (add or remove, only for member roles)", | ||
| ) | ||
| @app_commands.choices( | ||
| role_type=[ | ||
| app_commands.Choice(name="admin", value="admin"), | ||
| app_commands.Choice(name="member", value="member"), | ||
| ], | ||
| action=[ | ||
| app_commands.Choice(name="add", value="add"), | ||
| app_commands.Choice(name="remove", value="remove"), | ||
| ], | ||
| ) | ||
| async def set_role( | ||
| self, | ||
| interaction: discord.Interaction, | ||
| role_type: str, | ||
| role: discord.Role, | ||
| action: str = "add", # Default to "add" for member roles | ||
| ) -> None: | ||
| """Set a role by mentioning it.""" | ||
| if not interaction.guild: | ||
| await interaction.response.send_message("This must be used in a server.", ephemeral=True) | ||
| return | ||
|
|
||
| settings = self._ensure_settings(interaction.guild.id) | ||
|
|
||
| if role_type == "admin": | ||
| settings.admin_role = str(role.id) | ||
| await interaction.response.send_message(f"✅ Admin role set to {role.mention}!", ephemeral=True) | ||
| elif role_type == "member": | ||
| if action == "add": | ||
| if str(role.id) not in settings.member_roles: | ||
| settings.member_roles.append(str(role.id)) | ||
| await interaction.response.send_message(f"✅ Member role {role.mention} added!", ephemeral=True) | ||
| else: | ||
| await interaction.response.send_message( | ||
| f"⚠️ {role.mention} is already a member role.", ephemeral=True | ||
| ) | ||
| elif action == "remove": | ||
| if str(role.id) in settings.member_roles: | ||
| settings.member_roles.remove(str(role.id)) | ||
| await interaction.response.send_message(f"✅ Member role {role.mention} removed!", ephemeral=True) | ||
| else: | ||
| await interaction.response.send_message(f"⚠️ {role.mention} is not a member role.", ephemeral=True) | ||
|
|
||
| async def _show_summary(self, interaction: discord.Interaction, settings: GuildSettings) -> None: | ||
| """Display a summary of the current guild settings.""" | ||
|
|
||
| def _ch(cid: int | None) -> str: | ||
| return f"<#{cid}>" if cid else "Not set" | ||
|
|
||
| def _role(rid: str | None) -> str: | ||
| return f"<@&{rid}>" if rid else "Not set" | ||
|
|
||
| member_roles = ", ".join([f"<@&{rid}>" for rid in settings.member_roles]) or "Not set" | ||
|
|
||
| summary = ( | ||
| f"**Current Guild Settings:**\n" | ||
| f"- Announcements Channel: {_ch(settings.announcements_channel)}\n" | ||
| f"- Reports Channel: {_ch(settings.reports_channel)}\n" | ||
| f"- Feedback Channel: {_ch(settings.feedback_channel)}\n" | ||
| f"- Admin Role: {_role(settings.admin_role)}\n" | ||
| f"- Member Roles: {member_roles}\n" | ||
| f"- Onboarding Welcome: {settings.onboarding_welcome or 'Not set'}" | ||
| ) | ||
| await interaction.response.send_message(summary, ephemeral=True) | ||
|
|
||
|
|
||
| async def setup(bot: commands.Bot) -> None: | ||
| """Set up the Guild cog.""" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): Avoid using a mutable list as a default value on the model field.
Using
[]here means allGuildSettingsinstances share the same list object, which can cause cross-guild leakage of member roles. Use adefault_factory, e.g.member_roles: list[str] = Field(default_factory=list), so each instance gets its own list.