Compare commits

...

2 Commits

2 changed files with 67 additions and 20 deletions

2
.gitignore vendored
View File

@@ -27,3 +27,5 @@ Thumbs.db
# Runtime artifacts # Runtime artifacts
*.log *.log
.codex

View File

@@ -98,6 +98,9 @@ class TempVoiceDashboardView(discord.ui.View):
ephemeral=True, ephemeral=True,
) )
return return
allowed, _ = await self.cog._validate_interaction_access(interaction, channel)
if not allowed:
return
await interaction.response.send_modal(TempVoiceInputModal(self.cog, action, channel.id)) await interaction.response.send_modal(TempVoiceInputModal(self.cog, action, channel.id))
@discord.ui.button( @discord.ui.button(
@@ -318,7 +321,7 @@ class TempVoice(commands.Cog):
def _can_control_tempvoice_channel(self, member: discord.Member, owner_id: Optional[int]) -> bool: def _can_control_tempvoice_channel(self, member: discord.Member, owner_id: Optional[int]) -> bool:
if owner_id is None: if owner_id is None:
return False return False
return member.id == owner_id or member.guild_permissions.manage_guild return member.id == owner_id
async def _find_message_target( async def _find_message_target(
self, guild: discord.Guild, preferred_voice: Optional[discord.VoiceChannel] = None self, guild: discord.Guild, preferred_voice: Optional[discord.VoiceChannel] = None
@@ -344,10 +347,18 @@ class TempVoice(commands.Cog):
return ch return ch
return None return None
def _build_dashboard_embed(self, guild: discord.Guild, channel: discord.VoiceChannel, owner_id: int) -> discord.Embed: def _build_dashboard_embed(
self,
guild: discord.Guild,
channel: discord.VoiceChannel,
owner_id: int,
*,
is_private: Optional[bool] = None,
) -> discord.Embed:
everyone = guild.default_role everyone = guild.default_role
overwrite = channel.overwrites_for(everyone) overwrite = channel.overwrites_for(everyone)
is_private = overwrite.connect is False or overwrite.view_channel is False if is_private is None:
is_private = overwrite.connect is False or overwrite.view_channel is False
owner_mention = f"<@{owner_id}>" owner_mention = f"<@{owner_id}>"
member_mentions = ", ".join(m.mention for m in channel.members) if channel.members else _("No members") member_mentions = ", ".join(m.mention for m in channel.members) if channel.members else _("No members")
@@ -579,22 +590,28 @@ class TempVoice(commands.Cog):
return False, None return False, None
if not self._can_control_tempvoice_channel(interaction.user, owner_id): if not self._can_control_tempvoice_channel(interaction.user, owner_id):
await interaction.response.send_message( await interaction.response.send_message(
_("Only the channel owner (or server manager) can use this panel."), _("Only the current channel owner can use this panel."),
ephemeral=True, ephemeral=True,
) )
return False, owner_id return False, owner_id
return True, owner_id return True, owner_id
async def _send_interaction_notice(self, interaction: discord.Interaction, message: str) -> None:
if interaction.response.is_done():
await interaction.followup.send(message, ephemeral=True)
else:
await interaction.response.send_message(message, ephemeral=True)
async def handle_panel_button( async def handle_panel_button(
self, interaction: discord.Interaction, action: str, channel: Optional[discord.VoiceChannel] self, interaction: discord.Interaction, action: str, channel: Optional[discord.VoiceChannel]
): ):
allowed, _ = await self._validate_interaction_access(interaction, channel) allowed, owner_id = await self._validate_interaction_access(interaction, channel)
if not allowed or channel is None: if not allowed or channel is None:
return return
guild = interaction.guild guild = interaction.guild
assert guild is not None assert guild is not None
me = guild.me me = guild.me
if me is None or not guild.me.guild_permissions.manage_channels: if me is None or not channel.permissions_for(me).manage_channels:
await interaction.response.send_message( await interaction.response.send_message(
_("I need Manage Channels permission to modify this channel."), _("I need Manage Channels permission to modify this channel."),
ephemeral=True, ephemeral=True,
@@ -602,35 +619,53 @@ class TempVoice(commands.Cog):
return return
if action == "toggle_private": if action == "toggle_private":
await interaction.response.defer(ephemeral=True)
everyone = guild.default_role everyone = guild.default_role
ow = channel.overwrites_for(everyone) ow = channel.overwrites_for(everyone)
currently_private = ow.connect is False or ow.view_channel is False currently_private = ow.connect is False or ow.view_channel is False
new_is_private = not currently_private
if currently_private: if currently_private:
ow.connect = None
ow.view_channel = None
new_state = _("public") new_state = _("public")
else: else:
ow.connect = False
ow.view_channel = False
new_state = _("private") new_state = _("private")
try: try:
await channel.set_permissions( await channel.set_permissions(
everyone, overwrite=ow, reason=f"TempVoice panel toggle {new_state}" everyone,
view_channel=not new_is_private,
connect=not new_is_private,
reason=f"TempVoice panel toggle {new_state}",
) )
await interaction.response.send_message( if interaction.message is not None and owner_id is not None:
embed = self._build_dashboard_embed(
guild,
channel,
owner_id,
is_private=new_is_private,
)
await interaction.message.edit(embed=embed, view=self._dashboard_view)
await self._send_interaction_notice(
interaction,
_("Channel visibility changed. New state: {state}.").format(state=new_state), _("Channel visibility changed. New state: {state}.").format(state=new_state),
ephemeral=True,
) )
await self._refresh_dashboard_message(interaction, channel)
except discord.Forbidden: except discord.Forbidden:
await interaction.response.send_message( await self._send_interaction_notice(
interaction,
_("I cannot update channel permissions."), _("I cannot update channel permissions."),
ephemeral=True,
) )
except discord.HTTPException: except discord.HTTPException:
await interaction.response.send_message( await self._send_interaction_notice(
interaction,
_("Discord rejected the permission update."), _("Discord rejected the permission update."),
ephemeral=True, )
except Exception:
log.exception(
"Unexpected error while toggling TempVoice privacy for channel %s in guild %s.",
channel.id,
guild.id,
)
await self._send_interaction_notice(
interaction,
_("Unexpected error while updating channel permissions."),
) )
return return
@@ -658,6 +693,7 @@ class TempVoice(commands.Cog):
if me is None: if me is None:
await interaction.response.send_message(_("Bot state is not ready."), ephemeral=True) await interaction.response.send_message(_("Bot state is not ready."), ephemeral=True)
return return
bot_channel_perms = channel.permissions_for(me)
try: try:
if action == "change_limit": if action == "change_limit":
@@ -669,7 +705,7 @@ class TempVoice(commands.Cog):
if value < 0 or value > 99: if value < 0 or value > 99:
await interaction.response.send_message(_("User limit must be between 0 and 99."), ephemeral=True) await interaction.response.send_message(_("User limit must be between 0 and 99."), ephemeral=True)
return return
if not me.guild_permissions.manage_channels: if not bot_channel_perms.manage_channels:
await interaction.response.send_message( await interaction.response.send_message(
_("I need Manage Channels permission to change the user limit."), _("I need Manage Channels permission to change the user limit."),
ephemeral=True, ephemeral=True,
@@ -684,7 +720,7 @@ class TempVoice(commands.Cog):
return return
if action == "change_name": if action == "change_name":
if not me.guild_permissions.manage_channels: if not bot_channel_perms.manage_channels:
await interaction.response.send_message( await interaction.response.send_message(
_("I need Manage Channels permission to change channel name."), _("I need Manage Channels permission to change channel name."),
ephemeral=True, ephemeral=True,
@@ -709,8 +745,17 @@ class TempVoice(commands.Cog):
if target is None: if target is None:
await interaction.response.send_message(_("Could not find that member."), ephemeral=True) await interaction.response.send_message(_("Could not find that member."), ephemeral=True)
return return
previous_owner = guild.get_member(owner_id) if owner_id is not None else None
await self._set_channel_owner(guild, channel.id, target.id) await self._set_channel_owner(guild, channel.id, target.id)
await self._ensure_owner_permissions(channel, target) await self._ensure_owner_permissions(channel, target)
if previous_owner is not None and previous_owner.id != target.id:
previous_overwrite = channel.overwrites_for(previous_owner)
previous_overwrite.manage_channels = None
await channel.set_permissions(
previous_owner,
overwrite=previous_overwrite,
reason="TempVoice owner changed",
)
await interaction.response.send_message( await interaction.response.send_message(
_("Channel owner changed to {member}.").format(member=target.mention), _("Channel owner changed to {member}.").format(member=target.mention),
ephemeral=True, ephemeral=True,