Add waiting room functionality to AutoRoom cog
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run
This update introduces a waiting room system for AutoRoom sources, allowing users to be approved before entering the main AutoRoom. New commands for enabling and disabling waiting rooms have been added, along with corresponding settings in the configuration. The README has been updated to include instructions on using the waiting room feature.
This commit is contained in:
parent
7fc83b2022
commit
4c69cf7ab9
4 changed files with 273 additions and 0 deletions
|
@ -26,6 +26,31 @@ Start by having a voice channel, and a category (the voice channel does not need
|
|||
|
||||
This command will guide you through setting up an AutoRoom Source by asking some questions. If you get a warning about missing permissions, take a look at `[p]autoroomset permissions`, grant the missing permissions, and then run the command again. Otherwise, answer the questions, and you'll have a new AutoRoom Source. Give it a try by joining it: if all goes well, you will be moved to a new AutoRoom, where you can do all of the `[p]autoroom` commands.
|
||||
|
||||
### Waiting Room System
|
||||
|
||||
The waiting room system allows you to control who can join AutoRooms. When enabled, users will first join a waiting room where they must be approved by the AutoRoom owner before being allowed into the main AutoRoom.
|
||||
|
||||
To enable the waiting room system for an AutoRoom source:
|
||||
|
||||
```
|
||||
[p]autoroomset modify waitingroom enable <source_voice_channel>
|
||||
```
|
||||
|
||||
To disable it:
|
||||
|
||||
```
|
||||
[p]autoroomset modify waitingroom disable <source_voice_channel>
|
||||
```
|
||||
|
||||
When a user joins the waiting room:
|
||||
1. A message will appear in the AutoRoom's text channel with "Allow" and "Deny" buttons
|
||||
2. The AutoRoom owner can click these buttons to either:
|
||||
- Allow the user into the AutoRoom
|
||||
- Deny access and move them back to the waiting room
|
||||
3. If denied, the user will be added to the denied list and won't be able to join the AutoRoom again
|
||||
|
||||
Note: The waiting room system requires a text channel to be enabled for the AutoRoom source.
|
||||
|
||||
There are some additional configuration options for AutoRoom Sources that you can set by using `[p]autoroomset modify`. You can also check out `[p]autoroomset access`, which controls whether admins (default yes) or moderators (default no) can see and join private AutoRooms. For an overview of all of your settings, use `[p]autoroomset settings`.
|
||||
|
||||
#### Member Roles and Hidden Sources
|
||||
|
|
|
@ -15,6 +15,7 @@ from .c_autoroom import AutoRoomCommands
|
|||
from .c_autoroomset import AutoRoomSetCommands, channel_name_template
|
||||
from .pcx_lib import Perms, SettingDisplay
|
||||
from .pcx_template import Template
|
||||
from .waiting_room import WaitingRoom
|
||||
|
||||
|
||||
class CompositeMetaClass(type(commands.Cog), type(ABC)):
|
||||
|
@ -57,6 +58,9 @@ class AutoRoom(
|
|||
"channel_name_format": "",
|
||||
"perm_owner_manage_channels": True,
|
||||
"perm_send_messages": True,
|
||||
"waiting_room_enabled": False,
|
||||
"waiting_room_channel_id": None,
|
||||
"waiting_room_message_id": None,
|
||||
}
|
||||
default_channel_settings: ClassVar[dict[str, int | list[int] | None]] = {
|
||||
"source_channel": None,
|
||||
|
@ -112,6 +116,7 @@ class AutoRoom(
|
|||
)
|
||||
self.config.register_channel(**self.default_channel_settings)
|
||||
self.template = Template()
|
||||
self.waiting_room = WaitingRoom(self)
|
||||
self.bucket_autoroom_create = commands.CooldownMapping.from_cooldown(
|
||||
2, 60, lambda member: member
|
||||
)
|
||||
|
@ -357,6 +362,18 @@ class AutoRoom(
|
|||
bucket.update_rate_limit()
|
||||
|
||||
if isinstance(joining.channel, discord.VoiceChannel):
|
||||
# Check if user joined a waiting room
|
||||
config = await self.config.custom(
|
||||
"AUTOROOM_SOURCE",
|
||||
str(joining.channel.guild.id)
|
||||
).all()
|
||||
|
||||
for source_id, source_config in config.items():
|
||||
if source_config.get("waiting_room_enabled") and str(joining.channel.id) == str(source_config.get("waiting_room_channel_id")):
|
||||
# User joined a waiting room, handle it
|
||||
await self.waiting_room.handle_waiting_user(member, joining.channel)
|
||||
return
|
||||
|
||||
# If user entered an AutoRoom Source channel, create new AutoRoom
|
||||
asc = await self.get_autoroom_source_config(joining.channel)
|
||||
if asc:
|
||||
|
|
|
@ -973,6 +973,53 @@ class AutoRoomSetCommands(MixinMeta, ABC):
|
|||
)
|
||||
)
|
||||
|
||||
@modify.group(name="waitingroom")
|
||||
async def modify_waitingroom(
|
||||
self,
|
||||
ctx: commands.Context,
|
||||
) -> None:
|
||||
"""Modify waiting room settings."""
|
||||
pass
|
||||
|
||||
@modify_waitingroom.command(name="enable")
|
||||
async def modify_waitingroom_enable(
|
||||
self,
|
||||
ctx: commands.Context,
|
||||
autoroom_source: discord.VoiceChannel,
|
||||
) -> None:
|
||||
"""Enable waiting room for an AutoRoom source."""
|
||||
if not await self.get_autoroom_source_config(autoroom_source):
|
||||
await ctx.send("That is not an AutoRoom source.")
|
||||
return
|
||||
|
||||
# Get the text channel
|
||||
text_channel = await self.get_autoroom_legacy_text_channel(autoroom_source)
|
||||
if not text_channel:
|
||||
await ctx.send("This AutoRoom source needs a text channel enabled first.")
|
||||
return
|
||||
|
||||
# Set up waiting room
|
||||
success = await self.waiting_room.setup_waiting_room(autoroom_source, text_channel)
|
||||
if success:
|
||||
await ctx.send("Waiting room has been enabled for this AutoRoom source.")
|
||||
else:
|
||||
await ctx.send("Failed to set up waiting room. Please check my permissions.")
|
||||
|
||||
@modify_waitingroom.command(name="disable")
|
||||
async def modify_waitingroom_disable(
|
||||
self,
|
||||
ctx: commands.Context,
|
||||
autoroom_source: discord.VoiceChannel,
|
||||
) -> None:
|
||||
"""Disable waiting room for an AutoRoom source."""
|
||||
if not await self.get_autoroom_source_config(autoroom_source):
|
||||
await ctx.send("That is not an AutoRoom source.")
|
||||
return
|
||||
|
||||
# Clean up waiting room
|
||||
await self.waiting_room.cleanup_waiting_room(autoroom_source)
|
||||
await ctx.send("Waiting room has been disabled for this AutoRoom source.")
|
||||
|
||||
async def _check_all_perms(
|
||||
self, guild: discord.Guild, *, detailed: bool = False
|
||||
) -> tuple[bool, bool, list[str]]:
|
||||
|
|
184
autoroom/waiting_room.py
Normal file
184
autoroom/waiting_room.py
Normal file
|
@ -0,0 +1,184 @@
|
|||
"""Waiting room functionality for AutoRoom cog."""
|
||||
|
||||
from typing import Any, Optional
|
||||
|
||||
import discord
|
||||
from discord import ui
|
||||
from redbot.core import Config
|
||||
from redbot.core.bot import Red
|
||||
|
||||
class WaitingRoomView(ui.View):
|
||||
"""View for waiting room control buttons."""
|
||||
|
||||
def __init__(self, cog: Any):
|
||||
super().__init__(timeout=None)
|
||||
self.cog = cog
|
||||
|
||||
@discord.ui.button(label="Allow", style=discord.ButtonStyle.green, custom_id="waiting_room_allow")
|
||||
async def allow_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
"""Allow a user into the AutoRoom."""
|
||||
if not interaction.message:
|
||||
return
|
||||
|
||||
# Get the waiting user from the message
|
||||
waiting_user_id = int(interaction.message.content.split("User: <@")[1].split(">")[0])
|
||||
waiting_user = interaction.guild.get_member(waiting_user_id)
|
||||
|
||||
if not waiting_user:
|
||||
await interaction.response.send_message("User no longer in the server.", ephemeral=True)
|
||||
return
|
||||
|
||||
# Get the AutoRoom info
|
||||
autoroom_info = await self.cog.get_autoroom_info(interaction.channel)
|
||||
if not autoroom_info:
|
||||
await interaction.response.send_message("This is not an AutoRoom.", ephemeral=True)
|
||||
return
|
||||
|
||||
# Check if the interaction user is the owner
|
||||
if interaction.user.id != autoroom_info["owner"]:
|
||||
await interaction.response.send_message("Only the AutoRoom owner can use these buttons.", ephemeral=True)
|
||||
return
|
||||
|
||||
# Move the user to the AutoRoom
|
||||
try:
|
||||
await waiting_user.move_to(interaction.channel)
|
||||
await interaction.message.delete()
|
||||
await interaction.response.send_message(f"Allowed {waiting_user.mention} into the AutoRoom.", ephemeral=True)
|
||||
except discord.HTTPException:
|
||||
await interaction.response.send_message("Failed to move user to the AutoRoom.", ephemeral=True)
|
||||
|
||||
@discord.ui.button(label="Deny", style=discord.ButtonStyle.red, custom_id="waiting_room_deny")
|
||||
async def deny_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
"""Deny a user access to the AutoRoom."""
|
||||
if not interaction.message:
|
||||
return
|
||||
|
||||
# Get the waiting user from the message
|
||||
waiting_user_id = int(interaction.message.content.split("User: <@")[1].split(">")[0])
|
||||
waiting_user = interaction.guild.get_member(waiting_user_id)
|
||||
|
||||
if not waiting_user:
|
||||
await interaction.response.send_message("User no longer in the server.", ephemeral=True)
|
||||
return
|
||||
|
||||
# Get the AutoRoom info
|
||||
autoroom_info = await self.cog.get_autoroom_info(interaction.channel)
|
||||
if not autoroom_info:
|
||||
await interaction.response.send_message("This is not an AutoRoom.", ephemeral=True)
|
||||
return
|
||||
|
||||
# Check if the interaction user is the owner
|
||||
if interaction.user.id != autoroom_info["owner"]:
|
||||
await interaction.response.send_message("Only the AutoRoom owner can use these buttons.", ephemeral=True)
|
||||
return
|
||||
|
||||
# Add user to denied list
|
||||
denied = autoroom_info.get("denied", [])
|
||||
if waiting_user.id not in denied:
|
||||
denied.append(waiting_user.id)
|
||||
await self.cog.config.channel(interaction.channel).denied.set(denied)
|
||||
|
||||
# Move user back to waiting room
|
||||
waiting_room = interaction.guild.get_channel(autoroom_info["waiting_room_channel_id"])
|
||||
if waiting_room:
|
||||
try:
|
||||
await waiting_user.move_to(waiting_room)
|
||||
except discord.HTTPException:
|
||||
pass
|
||||
|
||||
await interaction.message.delete()
|
||||
await interaction.response.send_message(f"Denied {waiting_user.mention} access to the AutoRoom.", ephemeral=True)
|
||||
|
||||
class WaitingRoom:
|
||||
"""Handles waiting room functionality."""
|
||||
|
||||
def __init__(self, cog: Any):
|
||||
self.cog = cog
|
||||
self.bot: Red = cog.bot
|
||||
self.config: Config = cog.config
|
||||
|
||||
async def setup_waiting_room(self, autoroom_source: discord.VoiceChannel, text_channel: discord.TextChannel) -> bool:
|
||||
"""Set up the waiting room for an AutoRoom source."""
|
||||
try:
|
||||
# Create waiting room channel
|
||||
waiting_room = await autoroom_source.guild.create_voice_channel(
|
||||
name="Waiting Room",
|
||||
category=autoroom_source.category,
|
||||
reason="AutoRoom: Setting up waiting room."
|
||||
)
|
||||
|
||||
# Set up permissions
|
||||
perms = discord.PermissionOverwrite(
|
||||
view_channel=True,
|
||||
connect=True,
|
||||
speak=True,
|
||||
stream=True,
|
||||
use_voice_activation=True
|
||||
)
|
||||
await waiting_room.set_permissions(autoroom_source.guild.default_role, overwrite=perms)
|
||||
|
||||
# Save waiting room channel ID
|
||||
await self.config.custom(
|
||||
"AUTOROOM_SOURCE",
|
||||
str(autoroom_source.guild.id),
|
||||
str(autoroom_source.id)
|
||||
).waiting_room_channel_id.set(waiting_room.id)
|
||||
|
||||
# Enable waiting room
|
||||
await self.config.custom(
|
||||
"AUTOROOM_SOURCE",
|
||||
str(autoroom_source.guild.id),
|
||||
str(autoroom_source.id)
|
||||
).waiting_room_enabled.set(True)
|
||||
|
||||
return True
|
||||
except discord.HTTPException:
|
||||
return False
|
||||
|
||||
async def handle_waiting_user(self, member: discord.Member, autoroom: discord.VoiceChannel) -> None:
|
||||
"""Handle a user joining the waiting room."""
|
||||
autoroom_info = await self.cog.get_autoroom_info(autoroom)
|
||||
if not autoroom_info:
|
||||
return
|
||||
|
||||
# Get the text channel
|
||||
text_channel = await self.cog.get_autoroom_legacy_text_channel(autoroom)
|
||||
if not text_channel:
|
||||
return
|
||||
|
||||
# Create waiting message with buttons
|
||||
view = WaitingRoomView(self.cog)
|
||||
message = await text_channel.send(
|
||||
f"User: {member.mention} is waiting to join the AutoRoom.",
|
||||
view=view
|
||||
)
|
||||
|
||||
# Save message ID
|
||||
await self.config.channel(autoroom).waiting_room_message_id.set(message.id)
|
||||
|
||||
async def cleanup_waiting_room(self, autoroom_source: discord.VoiceChannel) -> None:
|
||||
"""Clean up the waiting room when disabling it."""
|
||||
config = await self.config.custom(
|
||||
"AUTOROOM_SOURCE",
|
||||
str(autoroom_source.guild.id),
|
||||
str(autoroom_source.id)
|
||||
).all()
|
||||
|
||||
if config["waiting_room_channel_id"]:
|
||||
waiting_room = autoroom_source.guild.get_channel(config["waiting_room_channel_id"])
|
||||
if waiting_room:
|
||||
try:
|
||||
await waiting_room.delete(reason="AutoRoom: Disabling waiting room.")
|
||||
except discord.HTTPException:
|
||||
pass
|
||||
|
||||
await self.config.custom(
|
||||
"AUTOROOM_SOURCE",
|
||||
str(autoroom_source.guild.id),
|
||||
str(autoroom_source.id)
|
||||
).waiting_room_enabled.set(False)
|
||||
await self.config.custom(
|
||||
"AUTOROOM_SOURCE",
|
||||
str(autoroom_source.guild.id),
|
||||
str(autoroom_source.id)
|
||||
).waiting_room_channel_id.set(None)
|
Loading…
Add table
Reference in a new issue