Skip to content

Commit

Permalink
App command error handling and core module migration
Browse files Browse the repository at this point in the history
  • Loading branch information
MattBSG committed Jun 10, 2024
1 parent 8ae4862 commit adb8f6a
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 73 deletions.
24 changes: 23 additions & 1 deletion bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,29 @@ async def setup_hook(self):
async def on_message(self, message):
return # Return so commands will not process, and main extension can process instead

bot = MechaBowser()
@bot.tree.error
async def on_app_command_error(interaction: discord.Interaction, exception):
if isinstance(exception, discord.app_commands.MissingRole) or isinstance(exception, discord.app_commands.MissingAnyRole):
return await interaction.response.send_message(f'{config.redTick} You do not have permission to run this command', ephemeral=True)

elif isinstance(exception, discord.app_commands.CommandOnCooldown):
return await interaction.response.send_message(f'{config.redTick} This command is on cooldown, please wait {exception.retry_after} seconds and try again', ephemeral=True)

elif isinstance(exception, discord.app_commands.CommandSignatureMismatch):
await interaction.response.send_message(f'{config.redTick} A temporary error occured when running that command. Please wait a bit, then try again', ephemeral=True)
logging.error(f'A command signature mismatch has occured, we will attempt to resync. Raising triggering exception')

guildObj = discord.Object(id=config.nintendoswitch)
await interaction.client.tree.sync(guild=guildObj)
raise exception

else:
# Unhandled, error to user and raise
await interaction.response.send_message(f'{config.redTick} A temporary error occured when running that command. Please wait a bit, then try again', ephemeral=True)
raise exception


if __name__ == '__main__':
print('\033[94mMechaBowser by MattBSG#8888 2019\033[0m')
asyncio.run(MechaBowser().start(config.token))
asyncio.run(bot.start(config.token))
134 changes: 62 additions & 72 deletions modules/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
from datetime import datetime, timezone

import config # type: ignore
import discord
import pymongo
import discord
from discord import app_commands
from discord.ext import commands, tasks

import tools # type: ignore
Expand Down Expand Up @@ -80,10 +81,12 @@ async def sanitize_eud(self):

logging.info('[Core] Finished sanitzation of old EUD')

@commands.command(name='ping')
async def _ping(self, ctx):
initiated = ctx.message.created_at
msg = await ctx.send('Evaluating...')
@app_commands.command(name='ping', description='Checks that the bot is responding normally and shows various latency values')
@app_commands.guilds(discord.Object(id=config.nintendoswitch))
@app_commands.default_permissions(view_audit_log=True)
async def _ping(self, interaction):
initiated = interaction.created_at
msg = await interaction.response.send_message('Evaluating...')
roundtrip = (msg.created_at - initiated).total_seconds() * 1000

database_start = time.time()
Expand All @@ -92,7 +95,7 @@ async def _ping(self, ctx):

websocket = self.bot.latency * 1000

return await msg.edit(
return await interaction.response.edit_message(
content=(
'Pong! Latency: **Roundtrip** `{:1.0f}ms`, **Websocket** `{:1.0f}ms`, **Database** `{:1.0f}ms`'.format(
roundtrip, websocket, database
Expand Down Expand Up @@ -696,78 +699,65 @@ async def on_guild_role_delete(self, role):
storedRoles.remove(role.id)
db.update_one({'_id': user['_id']}, {'$set': {'roles': storedRoles}})

@commands.Cog.listener()
async def on_command_error(self, context, exception):
if isinstance(exception, commands.CommandNotFound):
pass

else:
raise exception

@commands.command(name='update')
@commands.is_owner()
async def _update(self, ctx, sub, *args):
if sub == 'pfp':
if not ctx.message.attachments:
return await ctx.send(':warning: An attachment to change the picture to was not provided')

else:
attachment = await ctx.message.attachments[0].read()
await self.bot.user.edit(avatar=attachment)

return await ctx.send('Done.')

elif sub == 'name':
username = ''
for x in args:
username += f'{x} '

if len(username[:-1]) >= 32:
return await ctx.send(':warning: That username is too long.')

await self.bot.user.edit(username=username)
@app_commands.guilds(discord.Object(id=config.nintendoswitch))
@app_commands.default_permissions(manage_guild=True)
@app_commands.checks.has_any_role(config.moderator, config.eh)
class BotUpdateCommand(app_commands.Group):
pass

update_group = BotUpdateCommand(name='update', description='Update components of the bot')

@update_group.command(name='pfp', description='Update the bot profile picture')
@app_commands.describe(image='The image to use as the new profile picture')
async def _update_pfp(self, interaction: discord.Interaction, image: discord.Attachment):
await interaction.response.defer()
attachment = await image.read()
await self.bot.user.edit(avatar=attachment)

return await interaction.followup.send('Done.')

@update_group.command(name='name', description='Update the bot username')
@app_commands.describe(name='The new username')
async def _update_name(self, interaction: discord.Interaction, name: str):
await interaction.response.defer()
if len(name) >= 32:
return await interaction.followup.send(f'{config.redTick} That username is too long.')

await self.bot.user.edit(username=name)
return await interaction.followup.send('Done.')

@update_group.command(name='cache', description='Update the database message cache for the entire server. API and resource intensive')
async def _update_cache(self, interaction: discord.Interaction):
funcStart = time.time()
logging.info('[Core] Starting db message sync')
await interaction.send_message(
'Starting syncronization of db for all messages in server. This will take a conciderable amount of time.'
)

elif sub == 'servermsgcache':
funcStart = time.time()
logging.info('[Core] Starting db message sync')
await ctx.send(
'Starting syncronization of db for all messages in server. This will take a conciderable amount of time.'
)
for channel in ctx.guild.channels:
if not issubclass(channel.__class__, discord.abc.Messageable):
continue
for channel in interaction.guild.channels:
if not issubclass(channel.__class__, discord.abc.Messageable):
continue

await ctx.send(f'Starting syncronization for <#{channel.id}>')
# Because this will definitely exceed the interaction expiry, send messages to the channel directly
await interaction.channel.send(f'Starting syncronization for <#{channel.id}>')

try:
x, y = await self.store_message_cache(channel)
await ctx.send(
f'Syncronized <#{channel.id}>. Processed {x} messages and recorded meta data for {y} messages'
)
try:
x, y = await self.store_message_cache(channel)
await interaction.channel.send(
f'Syncronized <#{channel.id}>. Processed {x} messages and recorded meta data for {y} messages'
)

except (discord.Forbidden, discord.HTTPException):
await ctx.send(f'Failed to syncronize <#{channel.id}>')
except (discord.Forbidden, discord.HTTPException):
await interaction.channel.send(f'Failed to syncronize <#{channel.id}>')

timeToComplete = tools.humanize_duration(tools.resolve_duration(f'{int(time.time() - funcStart)}s'))
return await ctx.send(f'<@{ctx.author.id}> Syncronization completed. Took {timeToComplete}')
timeToComplete = tools.humanize_duration(tools.resolve_duration(f'{int(time.time() - funcStart)}s'))
return await interaction.channel.send(f'<@{interaction.user.id}> Syncronization completed. Took {timeToComplete}')

else:
return await ctx.send('Invalid sub command')

@commands.command(name='pundb')
@commands.is_owner()
async def _pundb(
self, ctx, _type, user, moderator, strTime, active: typing.Optional[bool], *, reason='-No reason specified-'
):
date = datetime.strptime(strTime, '%m/%d/%y')
expiry = None if not active else int(date.timestamp() + (60 * 60 * 24 * 30))
await tools.issue_pun(int(user), int(moderator), _type, reason, expiry, active, 'old', date.timestamp())
await ctx.send(f'{config.greenTick} Done')

@commands.command(name='shutdown')
@commands.is_owner()
async def _shutdown(self, ctx):
await ctx.send('Closing connection to discord and shutting down')
@app_commands.command(name='shutdown', description='Shutdown the bot and all modules')
@app_commands.guilds(discord.Object(id=config.nintendoswitch))
@app_commands.default_permissions(manage_guild=True)
async def _shutdown(self, interaction: discord.Interaction):
await interaction.response.send_message('Closing connection to discord and shutting down')
return await self.bot.close()

async def store_message_cache(self, channel):
Expand Down

0 comments on commit adb8f6a

Please sign in to comment.