fix(tempvoice): validate dashboard owner access and privacy toggle
This commit is contained in:
83
tempvoice.py
83
tempvoice.py
@@ -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,9 +347,17 @@ 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)
|
||||||
|
if is_private is None:
|
||||||
is_private = overwrite.connect is False or overwrite.view_channel is False
|
is_private = overwrite.connect is False or overwrite.view_channel is False
|
||||||
|
|
||||||
owner_mention = f"<@{owner_id}>"
|
owner_mention = f"<@{owner_id}>"
|
||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user