Writing a Ban Command - SinisterRectus/Discordia GitHub Wiki

This tutorial is will give you a basic understanding of some frequently used Discordia features, such as Events. Before starting this tutorial, if you haven't already, please do the previous tutorials before starting this one, as they provide essentials that this tutorial does not cover.

Step 1: Learning About Events

Events are a class of emitter. Without going into the nitty-gritty, events are emitted when something happens, such as when a new member joins, someone, sends a message, or when someone adds a reaction. To start listening to those events and their respective arguments, you assign a listener to the said event. A listener is a callback (a function). Then using those listeners, you execute some logic, such as sending a message, or in this case, banning a member.

Step 2: Setting up The Listener

For this tutorial, we'll be using the messageCreate event to detect when someone wants to use the command.

To detect this, we'll require the Discordia module and its client class. We assign this class to the variable 'client'. This variable represents the bot on the client-side and allows us to listen to any events from the client-side.

local discordia = require('discordia')
local client = discordia.Client()

Then we'll use the on method to assign a listener to the messageCreate event. Doing this will allow us to know when someone sends a message, such as hello or !ban @member. We'll also add a check to determine whether the member who sent the message is a bot or not because we do not want bots to interact with our bot!

client:on('messageCreate', function(message) -- Once a message is sent, this function will be executed.
  if message.author.bot then return end -- Make sure a bot cannot execute this command.

  -- We still need to implement more logic here!
end)

Step 3: Detecting The Command

Now that we have our listener set up, we need to detect if the message is a command, so it ignores any other messages such as hello. We also need to check if the text starts with !ban. To do this, we perform a variety of checks.

Does the message begin with our prefix? (We'll assume it's ! for this tutorial.) Is the command ban?

We do this by using Lua's string library. In this case, we'll be using string.sub. string.sub extracts a piece of the string. In this case, the first four characters to see if it matches our requirements above.

This code is the same as the last, just with our checks added.

client:on('messageCreate', function(message)
  if message.author.bot then return end

  if message.content:sub(1, 4) == '!ban' then
    -- If our message contains our command, we'll execute some logic here.
  end
end)

Step 4: Validating The Command

Now that we indeed do know that the user wants to execute the ban command, we need to check several things, such as does the executor have enough permissions? Are there any mentioned members?

client:on('messageCreate', function(message)
  if message.author.bot then return end

  if message.content:sub(1, 4) == '!ban' then
    local author = message.guild:getMember(message.author.id)
    local member = message.mentionedUsers.first

    if not member then
      -- The user have not mentioned any member to be banned
      message:reply("Please mention a member to ban!")
      return
    elseif not author:hasPermission("banMembers") then
      -- The user does not have enough permissions
      message:reply("You do not have `banMembers` permissions!")
      return
    end

    -- We still have to implement the actual banning logic here
  end
end)

Step 5: Banning

Now that we have our checks in place, it's time to do the actual banning. To do this, we'll take our message and check it's content for user mentions. Before every ban we will make sure the user who executed the command have a higher role than the banned member.

--[[
    DISCLAIMER: Due to current incorrect handling of message.mentionedUsers
    we will be using string patterns to detect mentioned users.
]]

-- Loads some helpful string functions such as string.startswith
discordia.extensions.string()

client:on('messageCreate', function(message)
    if message.author.bot then
        return -- Ignore messages sent by bots
    end
    if not message.guild then
        return -- Ignore messages not sent in a guild
    end
    --[[
        string.startswith returns true if the first argument startts with the second argument
        string.startswith('Hello World!', 'Hello') -> true
    ]]
    if message.content:startswith('!ban ') then
        -- Get the member object of the user calling the command
        local caller = message.guild:getMember(message.author)
        -- Confirm the caller has permissions to ban users before we do anything else
        if not caller:hasPermission('banMembers') then
            message:reply('You are missing the `banMembers` permission')
            return
        end
        -- Confirm the bot is actually able to ban users
        if not message.guild.me:hasPermission('banMembers') then
            message:reply('I am missing the `banMembers` permission')
            return
        end
        --[[
            Strip the command from the message
            string.sub('!ban @user#0000', 6) -> @user#0000
        ]]
        local argument = message.content:sub(6)
        --[[
            Check if the message contains a mention
            Read https://www.lua.org/manual/5.2/manual.html#6.4.1 if you'd like to learn what this pattern does
        ]]
        local id = argument:match('^<@!?(%d+)>$')
        if not id then
            -- The caller did not mention anyone.
            message:reply('Please mention a user to ban')
            return
        end
        -- Confirm the caller mentioned a valid user.
        local user = client:getUser(id)
        if not user then
            message:reply('Please mention a valid user')
            return
        end
        -- Try to get the member object of the mentioned user (if it exists)
        local member = message.guild:getMember(user)
        if member then
            -- Prevent the caller from banning members with a higher role
            if caller.highestRole.position < member.highestRole.position then
                message:reply('You are unable to ban '..member.mentionString..' as they have a higher role than you')
                return
            end
            -- Confirm the bot is able to ban the mentioned member
            if message.guild.me.highestRole.position < member.highestRole.position then
                message:reply('I am unable to ban '..member.mentionString..' as they have a higher role than me')
                return
            end
            -- Finally ban the member
            member:ban()
        else
            -- The mentioned user is not a member of the server so no need to check role positions
            message.guild:banUser(user)
        end
        message:reply('Banned '..member.mentionString)
    end
end)

Step 6: Running Your Bot

Now that setting up is finished, we have to add the run method to tell the client to start authentication and the bot.

To do this, add this line to the very end of your code.

client:run("Bot BOT_TOKEN")

Make sure to replace BOT_TOKEN with your actual bot token. Your code should look something like this now:

local discordia = require('discordia')
local client = discordia.Client()

client:on('messageCreate', function(message)
  if message.author.bot then return end

  if message.content:sub(1, 4) == '!ban' then
    local author = message.guild:getMember(message.author.id)
    local member = message.mentionedUsers.first

    if not member then
      -- The user have not mentioned any member to be banned
      message:reply("Please mention someone to ban!")
      return
    elseif not author:hasPermission("banMembers") then
      -- The user does not have enough permissions
      message:reply("You do not have the `banMembers` permissions!")
      return
    end

    for user in message.mentionedUsers:iter() do
      -- Check if mention isn't a reply
      if string.find(message.content, "<@[!]?" .. user.id .. ">") then
        member = message.guild:getMember(user.id)
        if author.highestRole.position > member.highestRole.position then
          member:ban()
        end
      end
    end
  end
end)

client:run("Bot BOT_TOKEN")

Prev: Writing Your First Bot

⚠️ **GitHub.com Fallback** ⚠️