From 8c8d3b02a86c5dde83439b9ef0e2c4ba853edc23 Mon Sep 17 00:00:00 2001 From: Alexander Terry Date: Tue, 12 Sep 2023 16:33:48 -0800 Subject: [PATCH] add auto-matic unmute and undeafen feature --- ...dd_unmuteanddeafen_feature_to_user_and_.py | 32 ++++++++++++++++++ alexBot/cogs/configs.py | 14 ++++++-- alexBot/cogs/smartHome.py | 17 ---------- alexBot/cogs/voiceCommands.py | 19 ++++++++++- alexBot/database.py | 33 +++++++++++++++++-- 5 files changed, 93 insertions(+), 22 deletions(-) create mode 100644 alembic/versions/1b5c4ba46fbe_add_unmuteanddeafen_feature_to_user_and_.py diff --git a/alembic/versions/1b5c4ba46fbe_add_unmuteanddeafen_feature_to_user_and_.py b/alembic/versions/1b5c4ba46fbe_add_unmuteanddeafen_feature_to_user_and_.py new file mode 100644 index 0000000..307cced --- /dev/null +++ b/alembic/versions/1b5c4ba46fbe_add_unmuteanddeafen_feature_to_user_and_.py @@ -0,0 +1,32 @@ +"""add unMuteAndDeafen Feature to user and guild config + +Revision ID: 1b5c4ba46fbe +Revises: ebe62bce51c4 +Create Date: 2023-09-12 16:21:19.190512 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '1b5c4ba46fbe' +down_revision: Union[str, None] = 'ebe62bce51c4' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('guildconfigs', sa.Column('allowUnMuteAndDeafenOnJoin', sa.Boolean(), server_default='false', nullable=False)) + op.add_column('userconfigs', sa.Column('unMuteAndDeafenOnJoin', sa.Boolean(), server_default='false', nullable=False)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('userconfigs', 'unMuteAndDeafenOnJoin') + op.drop_column('guildconfigs', 'allowUnMuteAndDeafenOnJoin') + # ### end Alembic commands ### diff --git a/alexBot/cogs/configs.py b/alexBot/cogs/configs.py index c0bae38..a99a289 100644 --- a/alexBot/cogs/configs.py +++ b/alexBot/cogs/configs.py @@ -60,7 +60,12 @@ async def value_autocomplete(self, interaction: discord.Interaction, guess: str) return [] @configUserCommandGroup.command(name="set", description="sets a config value") - @app_commands.choices(key=[app_commands.Choice(name=key, value=key) for key in UserConfig.__config_keys__]) + @app_commands.choices( + key=[ + app_commands.Choice(name=f"{key} - {UserConfig.__config_docs__[key]}", value=key) + for key in UserConfig.__config_keys__ + ] + ) @app_commands.autocomplete(value=value_autocomplete) async def user_setConfig(self, interaction: discord.Interaction, key: str, value: str): # it's a user! we don't need to confirm they can set the key. @@ -137,7 +142,12 @@ async def guild_showConfig(self, interaction: discord.Interaction): await interaction.response.send_message(embed=embed, ephemeral=False) @configGuildCommandGroup.command(name="set", description="sets a config value") - @app_commands.choices(key=[app_commands.Choice(name=key, value=key) for key in GuildConfig.__config_keys__]) + @app_commands.choices( + key=[ + app_commands.Choice(name=f"{key} - {GuildConfig.__config_docs__[key]}", value=key) + for key in GuildConfig.__config_keys__ + ] + ) @app_commands.autocomplete(value=value_autocomplete) async def guild_setConfig(self, interaction: discord.Interaction, key: str, value: str): if not interaction.guild: diff --git a/alexBot/cogs/smartHome.py b/alexBot/cogs/smartHome.py index f90d4eb..b92f4d1 100644 --- a/alexBot/cogs/smartHome.py +++ b/alexBot/cogs/smartHome.py @@ -265,23 +265,6 @@ async def on_voice_state_update( after.channel = oldAfter - if member.id in self.notifiable and before.channel and not after.channel and (before.mute or before.deaf): - # member we care about, left a channel - log.debug( - f"{member.display_name} left {before.channel.name}, waiting 5 minutes to see if they come back, then remembering to unmute them" - ) - await asyncio.sleep(300) - if member.voice: - log.debug(f"{member.display_name} came back, not unmuting") - return - log.debug(f"{member.display_name} did not come back, unmuting") - await self.bot.wait_for( - "voice_state_update", - check=lambda m, b, a: m.guild.id == member.guild.id and m.id == member.id and a.channel is not None, - timeout=None, - ) - await member.edit(mute=False, deafen=False) - async def send_notification(self, user: int, title: str, members: List[discord.Member]): log.debug(f"title: {title}") content = f"Current members in your channel are:\n{NEWLINE.join([f'{m.display_name} {render_voiceState(m)}' for m in members])}" diff --git a/alexBot/cogs/voiceCommands.py b/alexBot/cogs/voiceCommands.py index 2291e76..ad1913a 100644 --- a/alexBot/cogs/voiceCommands.py +++ b/alexBot/cogs/voiceCommands.py @@ -4,7 +4,7 @@ import discord from discord import VoiceState, app_commands -from alexBot.database import UserConfig, async_session, select +from alexBot.database import GuildConfig, UserConfig, async_session, select from alexBot.tools import Cog, render_voiceState @@ -166,6 +166,23 @@ async def on_voice_state_update(self, member, before: Optional[VoiceState], afte if len(before.channel.members) == 0: await before.channel.delete(reason="no one left") self.current_thatars.remove(before.channel.id) + guild = member.guild + async with async_session() as session: + gc = await session.scalar(select(GuildConfig).where(GuildConfig.userId == guild.id)) + if not gc: + gc = GuildConfig(guild.id) + session.add(gc) + await session.commit() + if gc.allowUnMuteAndDeafenOnJoin: # server allows it + uc = await session.scalar(select(UserConfig).where(UserConfig.userId == member.id)) + if not uc: + uc = UserConfig(member.id) + session.add(uc) + await session.commit() + if uc.unMuteAndDeafenOnJoin: # user wants it + if before.channel is None and after.channel is not None: + # initial join, we can just blindly unmute and undeafen + await member.edit(mute=False, deafen=False) @app_commands.guild_only() @app_commands.checks.bot_has_permissions(move_members=True) diff --git a/alexBot/database.py b/alexBot/database.py index 0d689f9..09155c4 100644 --- a/alexBot/database.py +++ b/alexBot/database.py @@ -68,27 +68,56 @@ class GuildConfig(Base): "privateOnePersonVCs", "transcribeVoiceMessages", "minecraft", + "allowUnMuteAndDeafenOnJoin", ] + __config_docs__ = { + "ayy": "whether or not sending `ayy` responds with `lmao` is enabled", + "veryCool": "whether or not starting a message with `thank you ` responds with `very cool`", + "tikTok": "whether or not the video reposter is enabled", + "collectVoiceData": "whether or not voice data is collected", + "firstAmendment": "whether or not saying `free speech` or `first amendment` responds with the XKCD comic # 1357", + "privateOnePersonVCs": "whether or not joining a voice channel with a user cap of 1 gives you permissions to move people into it", + "transcribeVoiceMessages": "whether or not voice messages are transcribed in chat", + "minecraft": "the minecraft server ip for the default to /minecraft", + "allowUnMuteAndDeafenOnJoin": "whether or not users are able to be un-server-muted and un-server-deafened when they join a voice channel", + } guildId: Mapped[int] = mapped_column(BIGINT(), primary_key=True) ayy: Mapped[bool] = mapped_column(Boolean(), default=False) - tikTok: Mapped[bool] = mapped_column(Boolean(), default=False) veryCool: Mapped[bool] = mapped_column(Boolean(), default=False) + tikTok: Mapped[bool] = mapped_column(Boolean(), default=False) collectVoiceData: Mapped[bool] = mapped_column(Boolean(), default=True) firstAmendment: Mapped[bool] = mapped_column(Boolean(), default=False) privateOnePersonVCs: Mapped[bool] = mapped_column(Boolean(), default=False) transcribeVoiceMessages: Mapped[bool] = mapped_column(Boolean(), default=False) minecraft: Mapped[str] = mapped_column(String(), default="") + allowUnMuteAndDeafenOnJoin: Mapped[bool] = mapped_column(Boolean(), server_default="false", default=False) class UserConfig(Base): __tablename__ = "userconfigs" - __config_keys__ = ["ringable", "collectVoiceData", "voiceModel", "voiceSleepMute", "dontVoiceSleep"] + __config_keys__ = [ + "ringable", + "collectVoiceData", + "voiceModel", + "voiceSleepMute", + "dontVoiceSleep", + "unMuteAndDeafenOnJoin", + ] + __config_docs__ = { + "ringable": "whether or not you can be rung using /ring", + "collectVoiceData": "whether or not your voice data is collected", + "voiceModel": "the model used to transcribe your voice using /voice tts", + "voiceSleepMute": "whether or not you are muted when /voice sleep is used", + "dontVoiceSleep": "whether or not you are deafened when /voice sleep is used", + "unMuteAndDeafenOnJoin": "if you are un-server-muted and un-server-deafened when you join a voice channel", + } userId: Mapped[int] = mapped_column(BIGINT(), primary_key=True) ringable: Mapped[bool] = mapped_column(Boolean(), default=True) collectVoiceData: Mapped[bool] = mapped_column(Boolean(), default=True) voiceModel: Mapped[str] = mapped_column(String(), server_default="", default="") voiceSleepMute: Mapped[bool] = mapped_column(Boolean(), default=False) dontVoiceSleep: Mapped[bool] = mapped_column(Boolean(), default=False) + unMuteAndDeafenOnJoin: Mapped[bool] = mapped_column(Boolean(), server_default="false", default=False) class VoiceName(Base):