From 32f9e6e2c828f192138e7383b79de43af3228314 Mon Sep 17 00:00:00 2001 From: Lemon4ksan Date: Sun, 2 Mar 2025 14:03:50 +0300 Subject: [PATCH] fix: Add more missing checks. --- MusicBot/cogs/general.py | 14 +++-- MusicBot/cogs/settings.py | 21 ++++++-- MusicBot/cogs/utils/voice_extension.py | 6 +-- MusicBot/cogs/voice.py | 72 ++++++++++++++++++-------- MusicBot/ui/find.py | 10 ++-- MusicBot/ui/menu.py | 2 +- 6 files changed, 86 insertions(+), 39 deletions(-) diff --git a/MusicBot/cogs/general.py b/MusicBot/cogs/general.py index bd7db3c..74584f7 100644 --- a/MusicBot/cogs/general.py +++ b/MusicBot/cogs/general.py @@ -176,7 +176,7 @@ class General(Cog): @account.command(description="Ввести токен Яндекс Музыки.") @discord.option("token", type=discord.SlashCommandOptionType.string, description="Токен.") async def login(self, ctx: discord.ApplicationContext, token: str) -> None: - logging.info(f"[GENERAL] Login command invoked by user {ctx.author.id} in guild {ctx.guild.id}") + logging.info(f"[GENERAL] Login command invoked by user {ctx.author.id} in guild {ctx.guild_id}") try: client = await YMClient(token).init() except UnauthorizedError: @@ -196,7 +196,7 @@ class General(Cog): @account.command(description="Удалить токен из базы данных бота.") async def remove(self, ctx: discord.ApplicationContext) -> None: - logging.info(f"[GENERAL] Remove command invoked by user {ctx.author.id} in guild {ctx.guild.id}") + logging.info(f"[GENERAL] Remove command invoked by user {ctx.author.id} in guild {ctx.guild_id}") if not await self.users_db.get_ym_token(ctx.user.id): logging.info(f"[GENERAL] No token found for user {ctx.author.id}") await ctx.respond('❌ Токен не указан.', delete_after=15, ephemeral=True) @@ -208,7 +208,7 @@ class General(Cog): @account.command(description="Получить плейлист «Мне нравится»") async def likes(self, ctx: discord.ApplicationContext) -> None: - logging.info(f"[GENERAL] Likes command invoked by user {ctx.author.id} in guild {ctx.guild.id}") + logging.info(f"[GENERAL] Likes command invoked by user {ctx.author.id} in guild {ctx.guild_id}") token = await self.users_db.get_ym_token(ctx.user.id) if not token: @@ -223,7 +223,13 @@ class General(Cog): await ctx.respond('❌ Неверный токен. Укажите новый через /account login.', delete_after=15, ephemeral=True) return - likes = await client.users_likes_tracks() + try: + likes = await client.users_likes_tracks() + except UnauthorizedError: + logging.warning(f"[GENERAL] Unknown token error for user {ctx.user.id}") + await ctx.respond("❌ Произошла неизвестная ошибка при попытке получения лайков. Пожалуйста, сообщите об этом разработчику.", delete_after=15, ephemeral=True) + return + if likes is None: logging.info(f"[GENERAL] Failed to fetch likes for user {ctx.user.id}") await ctx.respond('❌ Что-то пошло не так. Повторите попытку позже.', delete_after=15, ephemeral=True) diff --git a/MusicBot/cogs/settings.py b/MusicBot/cogs/settings.py index a3cdf7a..39ad4ad 100644 --- a/MusicBot/cogs/settings.py +++ b/MusicBot/cogs/settings.py @@ -1,3 +1,4 @@ +import logging from typing import Literal, cast import discord @@ -19,7 +20,12 @@ class Settings(Cog): @settings.command(name="show", description="Показать текущие настройки бота.") async def show(self, ctx: discord.ApplicationContext) -> None: - guild = await self.db.get_guild(ctx.guild.id, projection={'allow_change_connect': 1, 'vote_switch_track': 1, 'vote_add': 1}) + if not ctx.guild_id: + logging.warning("[SETTINGS] Show command invoked without guild_id") + await ctx.respond("❌ Эта команда может быть использована только на сервере.", ephemeral=True) + return + + guild = await self.db.get_guild(ctx.guild_id, projection={'allow_change_connect': 1, 'vote_switch_track': 1, 'vote_add': 1}) vote = "✅ - Переключение" if guild['vote_switch_track'] else "❌ - Переключение" vote += "\n✅ - Добавление в очередь" if guild['vote_add'] else "\n❌ - Добавление в очередь" @@ -49,20 +55,25 @@ class Settings(Cog): if not member.guild_permissions.manage_channels: await ctx.respond("❌ У вас нет прав для выполнения этой команды.", delete_after=15, ephemeral=True) return + + if not ctx.guild_id: + logging.warning("[SETTINGS] Toggle command invoked without guild_id") + await ctx.respond("❌ Эта команда может быть использована только на сервере.", ephemeral=True) + return - guild = await self.db.get_guild(ctx.guild.id, projection={ + guild = await self.db.get_guild(ctx.guild_id, projection={ 'vote_switch_track': 1, 'vote_add': 1, 'allow_change_connect': 1}) if vote_type == 'Переключение': - await self.db.update(ctx.guild.id, {'vote_switch_track': not guild['vote_switch_track']}) + await self.db.update(ctx.guild_id, {'vote_switch_track': not guild['vote_switch_track']}) response_message = "Голосование за переключение трека " + ("❌ выключено." if guild['vote_switch_track'] else "✅ включено.") elif vote_type == 'Добавление в очередь': - await self.db.update(ctx.guild.id, {'vote_add': not guild['vote_add']}) + await self.db.update(ctx.guild_id, {'vote_add': not guild['vote_add']}) response_message = "Голосование за добавление в очередь " + ("❌ выключено." if guild['vote_add'] else "✅ включено.") elif vote_type == 'Добавление/Отключение бота': - await self.db.update(ctx.guild.id, {'allow_change_connect': not guild['allow_change_connect']}) + await self.db.update(ctx.guild_id, {'allow_change_connect': not guild['allow_change_connect']}) response_message = f"Добавление/Отключение бота от канала теперь {'✅ разрешено' if not guild['allow_change_connect'] else '❌ запрещено'} участникам без прав управления каналом." else: diff --git a/MusicBot/cogs/utils/voice_extension.py b/MusicBot/cogs/utils/voice_extension.py index fb2c801..ce2023b 100644 --- a/MusicBot/cogs/utils/voice_extension.py +++ b/MusicBot/cogs/utils/voice_extension.py @@ -352,8 +352,8 @@ class VoiceExtension: Returns: bool: Check result. """ - if not ctx.user or not ctx.guild: - logging.warning("[VC_EXT] User or guild not found in context inside 'voice_check'") + if not ctx.user or not ctx.guild_id: + logging.warning("[VC_EXT] User or guild id not found in context inside 'voice_check'") await ctx.respond("❌ Что-то пошло не так. Попробуйте еще раз.", delete_after=15, ephemeral=True) return False @@ -379,7 +379,7 @@ class VoiceExtension: return False if check_vibe_privilage: - guild = await self.db.get_guild(ctx.guild.id, projection={'current_viber_id': 1, 'vibing': 1}) + guild = await self.db.get_guild(ctx.guild_id, projection={'current_viber_id': 1, 'vibing': 1}) if guild['vibing'] and ctx.user.id != guild['current_viber_id']: logging.debug("[VIBE] Context user is not the current viber") await ctx.respond("❌ Вы не можете взаимодействовать с чужой волной!", delete_after=15, ephemeral=True) diff --git a/MusicBot/cogs/voice.py b/MusicBot/cogs/voice.py index d052ae7..c4e1c35 100644 --- a/MusicBot/cogs/voice.py +++ b/MusicBot/cogs/voice.py @@ -203,16 +203,21 @@ class Voice(Cog, VoiceExtension): @voice.command(name="menu", description="Создать или обновить меню проигрывателя.") async def menu(self, ctx: discord.ApplicationContext) -> None: - logging.info(f"[VOICE] Menu command invoked by user {ctx.author.id} in guild {ctx.guild.id}") + logging.info(f"[VOICE] Menu command invoked by user {ctx.author.id} in guild {ctx.guild_id}") if await self.voice_check(ctx) and not await self.send_menu_message(ctx): await ctx.respond("❌ Не удалось создать меню.", ephemeral=True) @voice.command(name="join", description="Подключиться к голосовому каналу, в котором вы сейчас находитесь.") async def join(self, ctx: discord.ApplicationContext) -> None: - logging.info(f"[VOICE] Join command invoked by user {ctx.author.id} in guild {ctx.guild.id}") + logging.info(f"[VOICE] Join command invoked by user {ctx.author.id} in guild {ctx.guild_id}") + + if not ctx.guild_id: + logging.warning("[VOICE] Join command invoked without guild_id") + await ctx.respond("❌ Эта команда может быть использована только на сервере.", ephemeral=True) + return member = cast(discord.Member, ctx.author) - guild = await self.db.get_guild(ctx.guild.id, projection={'allow_change_connect': 1}) + guild = await self.db.get_guild(ctx.guild_id, projection={'allow_change_connect': 1}) await ctx.defer(ephemeral=True) if not member.guild_permissions.manage_channels and not guild['allow_change_connect']: @@ -234,13 +239,18 @@ class Voice(Cog, VoiceExtension): @voice.command(description="Заставить бота покинуть голосовой канал.") async def leave(self, ctx: discord.ApplicationContext) -> None: - logging.info(f"[VOICE] Leave command invoked by user {ctx.author.id} in guild {ctx.guild.id}") + logging.info(f"[VOICE] Leave command invoked by user {ctx.author.id} in guild {ctx.guild_id}") + + if not ctx.guild_id: + logging.warning("[VOICE] Leave command invoked without guild_id") + await ctx.respond("❌ Эта команда может быть использована только на сервере.", ephemeral=True) + return member = cast(discord.Member, ctx.author) - guild = await self.db.get_guild(ctx.guild.id, projection={'allow_change_connect': 1}) + guild = await self.db.get_guild(ctx.guild_id, projection={'allow_change_connect': 1}) if not member.guild_permissions.manage_channels and not guild['allow_change_connect']: - logging.info(f"[VOICE] User {ctx.author.id} does not have permissions to execute leave command in guild {ctx.guild.id}") + logging.info(f"[VOICE] User {ctx.author.id} does not have permissions to execute leave command in guild {ctx.guild_id}") await ctx.respond("❌ У вас нет прав для выполнения этой команды.", delete_after=15, ephemeral=True) return @@ -252,13 +262,18 @@ class Voice(Cog, VoiceExtension): await vc.disconnect(force=True) await ctx.respond("✅ Отключение успешно!", delete_after=15, ephemeral=True) - logging.info(f"[VOICE] Successfully disconnected from voice channel in guild {ctx.guild.id}") + logging.info(f"[VOICE] Successfully disconnected from voice channel in guild {ctx.guild_id}") else: await ctx.respond("❌ Бот не подключен к голосовому каналу.", delete_after=15, ephemeral=True) @queue.command(description="Очистить очередь треков и историю прослушивания.") async def clear(self, ctx: discord.ApplicationContext) -> None: - logging.info(f"[VOICE] Clear queue command invoked by user {ctx.author.id} in guild {ctx.guild.id}") + logging.info(f"[VOICE] Clear queue command invoked by user {ctx.author.id} in guild {ctx.guild_id}") + + if not ctx.guild_id: + logging.warning("[VOICE] Clear command invoked without guild_id") + await ctx.respond("❌ Эта команда может быть использована только на сервере.", ephemeral=True) + return if not await self.voice_check(ctx): return @@ -267,7 +282,7 @@ class Voice(Cog, VoiceExtension): channel = cast(discord.VoiceChannel, ctx.channel) if len(channel.members) > 2 and not member.guild_permissions.manage_channels: - logging.info(f"Starting vote for clearing queue in guild {ctx.guild.id}") + logging.info(f"Starting vote for clearing queue in guild {ctx.guild_id}") response_message = f"{member.mention} хочет очистить историю прослушивания и очередь треков.\n\n Выполнить действие?." message = cast(discord.Interaction, await ctx.respond(response_message, delete_after=60)) @@ -289,19 +304,24 @@ class Voice(Cog, VoiceExtension): ) return - await self.db.update(ctx.guild.id, {'previous_tracks': [], 'next_tracks': []}) + await self.db.update(ctx.guild_id, {'previous_tracks': [], 'next_tracks': []}) await ctx.respond("✅ Очередь и история сброшены.", delete_after=15, ephemeral=True) - logging.info(f"[VOICE] Queue and history cleared in guild {ctx.guild.id}") + logging.info(f"[VOICE] Queue and history cleared in guild {ctx.guild_id}") @queue.command(description="Получить очередь треков.") async def get(self, ctx: discord.ApplicationContext) -> None: - logging.info(f"[VOICE] Get queue command invoked by user {ctx.author.id} in guild {ctx.guild.id}") + logging.info(f"[VOICE] Get queue command invoked by user {ctx.author.id} in guild {ctx.guild_id}") + + if not ctx.guild_id: + logging.warning("[VOICE] Get command invoked without guild_id") + await ctx.respond("❌ Эта команда может быть использована только на сервере.", ephemeral=True) + return if not await self.voice_check(ctx): return await self.users_db.update(ctx.user.id, {'queue_page': 0}) - tracks = await self.db.get_tracks_list(ctx.guild.id, 'next') + tracks = await self.db.get_tracks_list(ctx.guild_id, 'next') if len(tracks) == 0: await ctx.respond("❌ Очередь пуста.", ephemeral=True) return @@ -309,11 +329,16 @@ class Voice(Cog, VoiceExtension): embed = generate_queue_embed(0, tracks) await ctx.respond(embed=embed, view=await QueueView(ctx).init(), ephemeral=True) - logging.info(f"[VOICE] Queue embed sent to user {ctx.author.id} in guild {ctx.guild.id}") + logging.info(f"[VOICE] Queue embed sent to user {ctx.author.id} in guild {ctx.guild_id}") @voice.command(description="Прервать проигрывание, удалить историю, очередь и текущий плеер.") async def stop(self, ctx: discord.ApplicationContext) -> None: - logging.info(f"[VOICE] Stop command invoked by user {ctx.author.id} in guild {ctx.guild.id}") + logging.info(f"[VOICE] Stop command invoked by user {ctx.author.id} in guild {ctx.guild_id}") + + if not ctx.guild_id: + logging.warning("[VOICE] Stop command invoked without guild_id") + await ctx.respond("❌ Эта команда может быть использована только на сервере.", ephemeral=True) + return if not await self.voice_check(ctx): return @@ -322,7 +347,7 @@ class Voice(Cog, VoiceExtension): channel = cast(discord.VoiceChannel, ctx.channel) if len(channel.members) > 2 and not member.guild_permissions.manage_channels: - logging.info(f"Starting vote for stopping playback in guild {ctx.guild.id}") + logging.info(f"Starting vote for stopping playback in guild {ctx.guild_id}") response_message = f"{member.mention} хочет полностью остановить проигрывание.\n\n Выполнить действие?." message = cast(discord.Interaction, await ctx.respond(response_message, delete_after=60)) @@ -351,7 +376,7 @@ class Voice(Cog, VoiceExtension): else: await ctx.respond("❌ Произошла ошибка при остановке воспроизведения.", delete_after=15, ephemeral=True) - @voice.command(name='vibe', description="Запустить Мою Волну.") + @voice.command(description="Запустить Мою Волну.") @discord.option( "запрос", parameter_name='name', @@ -360,15 +385,20 @@ class Voice(Cog, VoiceExtension): autocomplete=discord.utils.basic_autocomplete(get_vibe_stations_suggestions), required=False ) - async def user_vibe(self, ctx: discord.ApplicationContext, name: str | None = None) -> None: + async def vibe(self, ctx: discord.ApplicationContext, name: str | None = None) -> None: logging.info(f"[VOICE] Vibe (user) command invoked by user {ctx.user.id} in guild {ctx.guild_id}") if not await self.voice_check(ctx): return + + if not ctx.guild_id: + logging.warning("[VOICE] Vibe command invoked without guild_id") + await ctx.respond("❌ Эта команда может быть использована только на сервере.", ephemeral=True) + return - guild = await self.db.get_guild(ctx.guild.id, projection={'current_menu': 1, 'vibing': 1}) + guild = await self.db.get_guild(ctx.guild_id, projection={'current_menu': 1, 'vibing': 1}) if guild['vibing']: - logging.info(f"[VOICE] Action declined: vibing is already enabled in guild {ctx.guild.id}") + logging.info(f"[VOICE] Action declined: vibing is already enabled in guild {ctx.guild_id}") await ctx.respond("❌ Моя Волна уже включена. Используйте /voice stop, чтобы остановить воспроизведение.", delete_after=15, ephemeral=True) return @@ -411,7 +441,7 @@ class Voice(Cog, VoiceExtension): channel = cast(discord.VoiceChannel, ctx.channel) if len(channel.members) > 2 and not member.guild_permissions.manage_channels: - logging.info(f"Starting vote for starting vibe in guild {ctx.guild.id}") + logging.info(f"Starting vote for starting vibe in guild {ctx.guild_id}") if _type == 'user' and _id == 'onyourwave': station = "Моя Волна" diff --git a/MusicBot/ui/find.py b/MusicBot/ui/find.py index 1db1704..f795ade 100644 --- a/MusicBot/ui/find.py +++ b/MusicBot/ui/find.py @@ -18,7 +18,7 @@ class PlayButton(Button, VoiceExtension): async def callback(self, interaction: Interaction) -> None: logging.debug(f"[FIND] Callback triggered for type: '{type(self.item).__name__}'") - if not interaction.guild: + if not interaction.guild_id: logging.info("[FIND] No guild found in PlayButton callback") await interaction.respond("❌ Эта команда доступна только на серверах.", ephemeral=True, delete_after=15) return @@ -26,7 +26,7 @@ class PlayButton(Button, VoiceExtension): if not await self.voice_check(interaction): return - guild = await self.db.get_guild(interaction.guild.id, projection={'current_track': 1, 'current_menu': 1, 'vote_add': 1, 'vibing': 1}) + guild = await self.db.get_guild(interaction.guild_id, projection={'current_track': 1, 'current_menu': 1, 'vote_add': 1, 'vibing': 1}) if guild['vibing']: await interaction.respond("❌ Нельзя добавлять треки в очередь, пока запущена волна.", ephemeral=True, delete_after=15) return @@ -100,7 +100,7 @@ class PlayButton(Button, VoiceExtension): await response.add_reaction('❌') await self.db.update_vote( - interaction.guild.id, + interaction.guild_id, response.id, { 'positive_votes': list(), @@ -119,11 +119,11 @@ class PlayButton(Button, VoiceExtension): if guild['current_track']: logging.debug(f"[FIND] Adding tracks to queue") - await self.db.modify_track(interaction.guild.id, tracks, 'next', 'extend') + await self.db.modify_track(interaction.guild_id, tracks, 'next', 'extend') else: logging.debug(f"[FIND] Playing track") track = tracks.pop(0) - await self.db.modify_track(interaction.guild.id, tracks, 'next', 'extend') + await self.db.modify_track(interaction.guild_id, tracks, 'next', 'extend') if not await self.play_track(interaction, track): await interaction.respond('❌ Не удалось воспроизвести трек.', ephemeral=True, delete_after=15) diff --git a/MusicBot/ui/menu.py b/MusicBot/ui/menu.py index 22339ed..5447c18 100644 --- a/MusicBot/ui/menu.py +++ b/MusicBot/ui/menu.py @@ -593,7 +593,7 @@ class MenuView(View, VoiceExtension): if not self.ctx.guild_id: return self - self.guild = await self.db.get_guild(self.ctx.guild_id, projection={'repeat': 1, 'shuffle': 1, 'current_track': 1, 'vibing': 1}) + self.guild = await self.db.get_guild(self.ctx.guild_id, projection={'repeat': 1, 'shuffle': 1, 'current_track': 1, 'current_menu': 1, 'vibing': 1}) if self.guild['repeat']: self.repeat_button.style = ButtonStyle.success