Added basic command error handling

This commit is contained in:
Sven Heidemann 2022-07-19 14:03:14 +02:00
parent 2f92dfe22f
commit 47b8af57cd
14 changed files with 205 additions and 26 deletions

View File

@ -24,7 +24,11 @@
"Bot": {
"910199451145076828": {
"MessageDeleteTimer": 6
}
},
"Technicians": [
240160344557879316,
236592458664902657
]
},
"Base": {
"910199451145076828": {

View File

@ -22,7 +22,10 @@
"Bot": {
"910199451145076828": {
"MessageDeleteTimer": 2
}
},
"Technicians": [
240160344557879316
]
},
"Base": {
"910199451145076828": {

View File

@ -23,7 +23,11 @@
},
"910199451145076828": {
"MessageDeleteTimer": 2
}
},
"Technicians": [
240160344557879316,
236592458664902657
]
},
"Base": {
"650366049023295514": {

View File

@ -20,7 +20,11 @@
"Bot": {
"910199451145076828": {
"MessageDeleteTimer": 4
}
},
"Technicians": [
240160344557879316,
236592458664902657
]
},
"Base": {
"910199451145076828": {

View File

@ -11,6 +11,7 @@ from modules.base.command.afk_command import AFKCommand
from modules.base.command.help_command import HelpCommand
from modules.base.command.info_command import InfoCommand
from modules.base.command.ping_command import PingCommand
from modules.base.events.base_on_command_error_event import BaseOnCommandErrorEvent
from modules.moderator.command.purge_command import PurgeCommand
from modules.base.command.user_info_command import UserInfoCommand
from modules.base.events.base_on_member_join_event import BaseOnMemberJoinEvent
@ -47,6 +48,8 @@ class StartupDiscordExtension(StartupExtensionABC):
dc.add_command(PingCommand)
dc.add_command(UserInfoCommand)
""" events """
# on_command_error
dc.add_event(DiscordEventTypesEnum.on_command_error.value, BaseOnCommandErrorEvent)
# on_member_join
dc.add_event(DiscordEventTypesEnum.on_member_join.value, BaseOnMemberJoinEvent)
# on_member_remove

View File

@ -14,6 +14,7 @@
"goodbye_message": "Schade das du uns so schnell verlässt :("
},
"base": {
"technician_command_error_message": "Es gab ein Fehler mit dem Befehl: {} ausgelöst von {} -> {}\nDatum und Zeit: {}\nSchau bitte ins log für Details.",
"welcome_message": "Hello There!\nIch heiße dich bei {} herzlichst willkommen!",
"welcome_message_for_team": "{} hat gerade das Irrenhaus betreten.",
"purge_message": "Na gut..., ich lösche alle Nachrichten wenns sein muss.",

View File

@ -12,16 +12,16 @@ class MessageServiceABC(ABC):
def __init__(self): pass
@abstractmethod
async def delete_messages(self, messages: List[discord.Message], guild_id: int): pass
async def delete_messages(self, messages: List[discord.Message], guild_id: int, without_tracking=False): pass
@abstractmethod
async def delete_message(self, message: discord.Message): pass
async def delete_message(self, message: discord.Message, without_tracking=False): pass
@abstractmethod
async def send_channel_message(self, channel: discord.TextChannel, message: Union[str, discord.Embed]): pass
async def send_channel_message(self, channel: discord.TextChannel, message: Union[str, discord.Embed], without_tracking=True): pass
@abstractmethod
async def send_dm_message(self, message: Union[str, discord.Embed], receiver: Union[discord.User, discord.Member]): pass
async def send_dm_message(self, message: Union[str, discord.Embed], receiver: Union[discord.User, discord.Member], without_tracking=False): pass
@abstractmethod
async def send_ctx_msg(self, ctx: Context, message: Union[str, discord.Embed], file: discord.File = None, is_persistent: bool = False, wait_before_delete: int = None): pass
async def send_ctx_msg(self, ctx: Context, message: Union[str, discord.Embed], file: discord.File = None, is_persistent: bool = False, wait_before_delete: int = None, without_tracking=True): pass

View File

@ -13,17 +13,24 @@ class BotSettings(ConfigurationModelABC):
ConfigurationModelABC.__init__(self)
self._servers: List[ServerSettings] = List()
self._technicians: list[int] = []
@property
def servers(self) -> List[ServerSettings]:
return self._servers
@property
def technicians(self) -> list[int]:
return self._technicians
def from_dict(self, settings: dict):
try:
self._technicians = settings["Technicians"]
settings.pop("Technicians")
servers = List(ServerSettings)
for s in settings:
st = ServerSettings()
settings[s]['Id'] = s
settings[s]["Id"] = s
st.from_dict(settings[s])
servers.append(st)
self._servers = servers

View File

@ -23,15 +23,15 @@ class MessageService(MessageServiceABC):
self._clients = clients
self._db = db
async def delete_messages(self, messages: List[discord.Message], guild_id: int):
async def delete_messages(self, messages: List[discord.Message], guild_id: int, without_tracking=False):
self._logger.debug(__name__, f'Try to delete {messages.count()} messages')
server_st: ServerSettings = self._config.get_configuration(f'ServerSettings_{guild_id}')
await asyncio.sleep(server_st.message_delete_timer)
for message in messages:
await self.delete_message(message, mass_delete=True)
await self.delete_message(message, mass_delete=True, without_tracking=without_tracking)
self._logger.debug(__name__, 'Deleting messages finished')
async def delete_message(self, message: discord.Message, mass_delete=False):
async def delete_message(self, message: discord.Message, mass_delete=False, without_tracking=False):
server_st: ServerSettings = self._config.get_configuration(f'ServerSettings_{message.guild.id}')
if not mass_delete:
await asyncio.sleep(server_st.message_delete_timer)
@ -42,11 +42,12 @@ class MessageService(MessageServiceABC):
except Exception as e:
self._logger.error(__name__, f'Deleting message failed', e)
else:
if not without_tracking:
self._clients.append_deleted_message_count(self._bot.user.id, guild_id, 1)
self._db.save_changes()
self._logger.info(__name__, f'Deleted message {message}')
async def send_channel_message(self, channel: discord.TextChannel, message: Union[str, discord.Embed]):
async def send_channel_message(self, channel: discord.TextChannel, message: Union[str, discord.Embed], without_tracking=False):
self._logger.debug(__name__, f'Try to send message\n\t{message}\n\tto: {channel}')
msg = None
try:
@ -58,11 +59,12 @@ class MessageService(MessageServiceABC):
self._logger.error(__name__, f'Send message to channel {channel.id} failed', e)
else:
self._logger.info(__name__, f'Sent message to channel {channel.id}')
if not without_tracking:
self._clients.append_sent_message_count(self._bot.user.id, channel.guild.id, 1)
self._db.save_changes()
await self.delete_message(msg)
await self.delete_message(msg, without_tracking)
async def send_dm_message(self, message: Union[str, discord.Embed], receiver: Union[discord.User, discord.Member]):
async def send_dm_message(self, message: Union[str, discord.Embed], receiver: Union[discord.User, discord.Member], without_tracking=False):
self._logger.debug(__name__, f'Try to send message\n\t{message}\n\tto: {receiver}')
try:
if isinstance(message, discord.Embed):
@ -72,11 +74,12 @@ class MessageService(MessageServiceABC):
except Exception as e:
self._logger.error(__name__, f'Send message to user {receiver.id} failed', e)
else:
if not without_tracking:
self._clients.append_sent_message_count(self._bot.user.id, receiver.guild.id, 1)
self._db.save_changes()
self._logger.info(__name__, f'Sent message to user {receiver.id}')
async def send_ctx_msg(self, ctx: Context, message: Union[str, discord.Embed], file: discord.File = None, is_persistent: bool = False, wait_before_delete: int = None):
async def send_ctx_msg(self, ctx: Context, message: Union[str, discord.Embed], file: discord.File = None, is_persistent: bool = False, wait_before_delete: int = None, without_tracking=False):
if ctx is None:
self._logger.warn(__name__, 'Message context is empty')
self._logger.debug(__name__, f'Message: {message}')
@ -93,13 +96,18 @@ class MessageService(MessageServiceABC):
self._logger.error(__name__, f'Send message to channel {ctx.channel.id} failed', e)
else:
self._logger.info(__name__, f'Sent message to channel {ctx.channel.id}')
if not without_tracking:
self._clients.append_sent_message_count(self._bot.user.id, ctx.guild.id, 1)
self._db.save_changes()
if wait_before_delete is not None:
await asyncio.sleep(wait_before_delete)
if is_persistent:
await self.delete_message(ctx.message)
await self.delete_message(ctx.message, without_tracking)
return
if ctx.guild is None:
self._logger.error(__name__, f'Error in {__name__}.send_ctx_msg: Guild is None')
return
await self.delete_messages(List(discord.Message, [msg, ctx.message]), ctx.guild.id)

View File

@ -35,6 +35,7 @@ class AFKCommand(DiscordCommandABC):
self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}')
@commands.command()
@commands.guild_only()
async def afk(self, ctx: Context):
self._logger.debug(__name__, f'Received command afk {ctx}')
self._client_utils.received_command(ctx.guild.id)

View File

@ -33,5 +33,6 @@ class PingCommand(DiscordCommandABC):
async def ping(self, ctx: Context):
self._logger.debug(__name__, f'Received command ping {ctx}')
self._client_utils.received_command(ctx.guild.id)
raise Exception('Dies ist ein test, ob ich dir eine Benachrichtung über Fehler sende')
await self._message_service.send_ctx_msg(ctx, self._t.transform('modules.base.pong'))
self._logger.trace(__name__, f'Finished ping command')

View File

@ -51,6 +51,7 @@ class UserInfoCommand(DiscordCommandABC):
self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}')
@commands.command(name='user-info')
@commands.guild_only()
async def user_info(self, ctx: Context, member: Optional[discord.Member] = None, *, wait: int = None):
self._logger.debug(__name__, f'Received command user-info {ctx}:{member},{wait}')
self._client_utils.received_command(ctx.guild.id)

View File

@ -0,0 +1,141 @@
import datetime
from cpl_core.time import TimeFormatSettings
from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe
from discord.ext import commands
from discord.ext.commands import Context, CommandError
from cpl_core.logging import LoggerABC
from cpl_discord.events.on_command_error_abc import OnCommandErrorABC
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.configuration.bot_settings import BotSettings
class BaseOnCommandErrorEvent(OnCommandErrorABC):
def __init__(
self,
logger: LoggerABC,
bot: DiscordBotServiceABC,
messenger: MessageServiceABC,
bot_settings: BotSettings,
time_format_settings: TimeFormatSettings,
translate: TranslatePipe
):
OnCommandErrorABC.__init__(self)
self._logger = logger
self._bot = bot
self._messenger = messenger
self._bot_settings = bot_settings
self._time_format_settings = time_format_settings
self._t = translate
async def on_command_error(self, ctx: Context, error: CommandError):
error = getattr(error, 'original', error)
# Todo: translate error messages !!!
if isinstance(error, commands.MissingRequiredArgument):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Ein benötigter Parameter fehlt!', without_tracking=True)
elif isinstance(error, commands.ArgumentParsingError):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Parameter konnte nicht gelesen werden!', without_tracking=True)
elif isinstance(error, commands.UnexpectedQuoteError):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Unerwarteter Zitat Fehler!', without_tracking=True)
elif isinstance(error, commands.InvalidEndOfQuotedStringError):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Ungültiges Zitatende!', without_tracking=True)
elif isinstance(error, commands.ExpectedClosingQuoteError):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Erwarte Zitatende!', without_tracking=True)
elif isinstance(error, commands.BadArgument):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Ungültiger Parameter!', without_tracking=True)
elif isinstance(error, commands.BadUnionArgument):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Ungültiger Union Parameter!', without_tracking=True)
elif isinstance(error, commands.PrivateMessageOnly):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Nur private Nachrichten sind erlaubt!', without_tracking=True)
elif isinstance(error, commands.NoPrivateMessage):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Private Nachrichten sind nicht erlaubt!', without_tracking=True)
elif isinstance(error, commands.CheckFailure):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Du hast nicht die benötigte Berechtigung!', without_tracking=True)
elif isinstance(error, commands.CheckAnyFailure):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Alle checks sind Fehlgeschlagen!', without_tracking=True)
elif isinstance(error, commands.CommandNotFound):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Befehl konnte nicht gefunden werden!', without_tracking=True)
elif isinstance(error, commands.DisabledCommand):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Befehl wurde deaktiviert!', without_tracking=True)
elif isinstance(error, commands.CommandInvokeError):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Befehl konnte nicht aufgerufen werden!', without_tracking=True)
elif isinstance(error, commands.TooManyArguments):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Zu viele Parameter!', without_tracking=True)
elif isinstance(error, commands.UserInputError):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Eingabefehler!', without_tracking=True)
elif isinstance(error, commands.CommandOnCooldown):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Befehl befindet sich im cooldown!', without_tracking=True)
elif isinstance(error, commands.MaxConcurrencyReached):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Maximale Parallelität erreicht!', without_tracking=True)
elif isinstance(error, commands.NotOwner):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Du bist nicht mein besitzer!', without_tracking=True)
elif isinstance(error, commands.MissingPermissions):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Berechtigungen fehlen!', without_tracking=True)
elif isinstance(error, commands.BotMissingPermissions):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Mir fehlen Berechtigungen!', without_tracking=True)
elif isinstance(error, commands.MissingRole):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Benötigte Rolle fehlt!', without_tracking=True)
elif isinstance(error, commands.BotMissingRole):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Mir fehlt eine benötigte Rolle!', without_tracking=True)
elif isinstance(error, commands.MissingAnyRole):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Alle benötigten Rollen fehlen!', without_tracking=True)
elif isinstance(error, commands.BotMissingAnyRole):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Mir fehlen alle benötigten Rollen!', without_tracking=True)
elif isinstance(error, commands.NSFWChannelRequired):
await self._messenger.send_ctx_msg(ctx, 'Fehler: NSFW Kanal benötigt!', without_tracking=True)
elif isinstance(error, commands.ExtensionError):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Erweiterungsfehler!', without_tracking=True)
elif isinstance(error, commands.ExtensionAlreadyLoaded):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Erweiterung wurde bereits geladen!', without_tracking=True)
elif isinstance(error, commands.ExtensionNotLoaded):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Erweiterung wurde nicht geladen!', without_tracking=True)
elif isinstance(error, commands.NoEntryPointError):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Kein Eintrittspunkt!', without_tracking=True)
elif isinstance(error, commands.ExtensionFailed):
await self._messenger.send_ctx_msg(ctx, 'Fehler: Erweiterung ist fehlgeschlagen!', without_tracking=True)
else:
message = self._t.transform('modules.base.technician_command_error_message').format(
ctx.command,
ctx.author,
error,
datetime.datetime.now().strftime(self._time_format_settings.date_time_format)
)
for t in self._bot_settings.technicians:
member = self._bot.get_user(t)
await self._messenger.send_dm_message(message, member, without_tracking=True)

View File

@ -36,6 +36,7 @@ class PurgeCommand(DiscordCommandABC):
self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}')
@commands.command()
@commands.guild_only()
async def purge(self, ctx: Context):
self._logger.debug(__name__, f'Received command purge {ctx}')
self._client_utils.received_command(ctx.guild.id)