Part 8 - Command Checks#
For this section, we’ll be making a purge
command, which will delete messages in bulk.
You don’t want just anyone to be able to use this command, only those who can delete messages themselves, so we’re gonna need to add some command checks to ensure that!
So, create a new file named mod.py
in the extensions folder.
In it paste the following:
1import datetime
2
3import hikari
4import lightbulb
5
6mod_plugin = lightbulb.Plugin("Mod")
7
8
9@mod_plugin.command
10@lightbulb.option(
11 "sent_by",
12 "Only purge messages sent by this user.",
13 type=hikari.User,
14 required=False,
15)
16@lightbulb.option(
17 "messages",
18 "The number of messages to purge.",
19 type=int,
20 required=True,
21 min_value=2,
22 max_value=200,
23)
24@lightbulb.command("purge", "Purge messages.", auto_defer=True)
25@lightbulb.implements(lightbulb.SlashCommand)
26async def purge_messages(ctx: lightbulb.SlashContext) -> None:
27 num_msgs = ctx.options.messages
28 sent_by = ctx.options.sent_by
29 channel = ctx.channel_id
30
31 bulk_delete_limit = datetime.datetime.now(
32 datetime.timezone.utc
33 ) - datetime.timedelta(days=14)
34
35 iterator = (
36 ctx.bot.rest.fetch_messages(channel)
37 .take_while(lambda msg: msg.created_at > bulk_delete_limit)
38 .filter(lambda msg: not (msg.flags & hikari.MessageFlag.LOADING))
39 )
40 if sent_by:
41 iterator = iterator.filter(lambda msg: msg.author.id == sent_by.id)
42
43 iterator = iterator.limit(num_msgs)
44
45 count = 0
46
47 async for messages in iterator.chunk(100):
48 count += len(messages)
49 await ctx.bot.rest.delete_messages(channel, messages)
50
51 await ctx.respond(f"{count} messages deleted.", delete_after=5)
52
53
54def load(bot: lightbulb.BotApp) -> None:
55 bot.add_plugin(mod_plugin)
Line 10-23 - Set up the command options
For the
messages
option, we’ve set limits.
When bulk deleting messages, Discord says you must have a minimum value of2
messages. And because we don’t want our bot to get rate limited while deleting huge amounts of messages, we also set our own maximum value of200
.
Line 24 - Pass a new kwarg
auto_defer
, setting it toTrue
This will respond to the command with a
DEFERRED
response type, showing the user a"<bot name> is thinking..."
message until we respond properly after deleting the messages
Line 27-28 - If we don’t use
pass_options=True
in the command decorator (like with theuserinfo
command), we can’t pass the options as function parameters, but their values can still be accessed viactx.options
Line 31-33 - Bots can’t bulk delete messages older than 2 weeks, so we set a limit to only fetch messages younger than 2 weeks
Line 35-43
Line 36 - Create an iterator which fetches the most recent messages in the channel
Read the docs - fetch_messages
Read the docs -LazyIterator
Line 37 - Take only the messages younger than 2 weeks
Read the docs -.take_while()
Line 38 - Filter the iterator, ignoring messages that have the
LOADING
message flag. These are the messages that display"<bot name> is thinking..."
Read the docs -.filter()
Line 40-41 - If a
sent_by
user was provided, then filter the iterator to only fetch messages sent by that userLine 43 - Finally, after all our filters have been applied, limit the number of messages to fetch
Line 47-49 - Delete the messages in the iterator, in chunks of 100
A maximum of 100 messages can be passed per bulk delete request, so we chunk them into groups of 100 and make multiple requests
This command works fine, but now everyone can delete messages using the bot. We only want people with the Manage Messages
permission to do this, so this is where checks come in.
Just below line 9 (@mod_plugin.command
), add the following:
@lightbulb.app_command_permissions(hikari.Permissions.MANAGE_MESSAGES, dm_enabled=False)
@lightbulb.add_checks(
lightbulb.bot_has_guild_permissions(hikari.Permissions.MANAGE_MESSAGES),
)
Line 1 - Using Discord’s app command permissions, we set default permissions of
MANAGE_MESSAGES
for the user, and we disable the command in DMsLine 2-4 - Check the bot also has permission to delete messages in the guild.
If the both the user and bot have permission to run the command, it will work. However if the bot doesn’t have the MANAGE_MESSAGES
permission, the command will raise CheckFailure.
But raising an error and the command failing isn’t that useful, we want to tell the user what happened.
So, onto error handling!