Class: CommandrbBot

Inherits:
Object
  • Object
show all
Defined in:
lib/helper.rb,
lib/commandrb.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(init_hash) ⇒ CommandrbBot

Returns a new instance of CommandrbBot.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/commandrb.rb', line 39

def initialize(init_hash)
  @debug_mode = ENV['COMMANDRB_MODE'] == 'debug'

  # Setup the variables for first use.
  @commands = {}
  @prefixes = []
  @config = init_hash

  # Load sane defaults for options that aren't specified.

  @config[:typing_default] = false if @config[:typing_default].nil?
  @config[:delete_activators] = false if @config[:delete_activators].nil?

  raise 'No token supplied in init hash!' if @config[:token].nil? || (init_hash[:token] == '')

  init_parse_self = begin
    init_hash[:parse_self]
  rescue StandardError
    nil
  end
  init_type = @config[:type]

  if init_type == :bot && init_hash[:client_id].nil?
    raise 'No client ID or invalid client ID supplied in init hash!'
  end

  @config[:owners] = init_hash[:owners]
  @config[:owners] = [] if @config[:owners].nil?

  @prefixes = init_hash[:prefixes]

  @bot = Discordrb::Bot.new(
    token: @config[:token],
    client_id: @config[:client_id],
    parse_self: init_parse_self,
    type: @config[:type]
  )

  unless init_hash[:ready].nil?
    @bot.ready do |event|
      event.bot.game = @config[:game] unless config[:game].nil?
      init_hash[:ready].call(event)
    end
  end

  # Command processing
  @bot.message do |event|
    chosen_activator = nil
    message_content = nil
    chosen_command = nil
    used_prefix = ''

    # If we have a usable prefix, get the raw arguments for this command.
    @prefixes.each do |prefix|
      next unless event.message.content.start_with?(prefix)

      # Store the message's content, sans its prefix.
      # Strip leading spaces in the event a prefix ends with a space.
      message_content = event.message.content
      used_prefix = message_content.slice! prefix
      break
    end

    # Otherwise, do not continue processing.
    next if message_content.nil?

    @commands.each do |key, command|
      puts ":: Considering #{key}" if @debug_mode == true
      triggers = command[:triggers].nil? ? [key.to_s] : command[:triggers]

      triggers.each do |trigger|
        activator = trigger.to_s.downcase
        puts activator if @debug_mode == true
        next unless event.message.content.downcase.start_with?(activator)

        puts "Prefix matched! #{activator}" if @debug_mode == true

        # Continue only if you've already chosen a choice.
        if chosen_activator.nil?
          puts 'First match obtained!' if @debug_mode == true
          chosen_activator = activator
          chosen_command = command

          # If the new activator begins with the chosen one, then override it.
          # Example: sh is chosen, shell is the new one.
          # In this example, shell would override sh, preventing ugly bugs.
        elsif activator.start_with?(chosen_activator)
          puts "#{activator} just overrode #{chosen_activator}" if @debug_mode == true
          chosen_activator = activator
          chosen_command = command
        # Otherwise, just give up.
        elsif @debug_mode == true
          puts 'Match failed...'
        end
        # If you haven't chosen yet, get choosing!
      end

      puts "Result: #{chosen_activator}" if @debug_mode == true
    end

    # If we have no chosen activator, it is likely the command does not exist
    # or the prefix itself was run.
    next if chosen_activator.nil?

    command_run = used_prefix + chosen_activator
    puts "Final result: #{command_run}" if @debug_mode == true

    # Command flag defaults
    chosen_command[:owners_only] = false if chosen_command[:owners_only].nil?
    chosen_command[:server_only] = false if chosen_command[:server_only].nil?
    chosen_command[:typing] = @config[:typing_default] if chosen_command[:typing_default].nil?
    if chosen_command[:delete_activator].nil?
      chosen_command[:delete_activator] =
        @config[:delete_activators]
    end
    chosen_command[:owner_override] = false if chosen_command[:owner_override].nil?

    # If the settings are to delete activating messages, then do that.
    # I'm *hoping* this doesn't cause issues with argument extraction.
    event.message.delete if chosen_command[:delete_activator]

    # If the command is only for use in servers, display error and abort.
    if chosen_command[:server_only] && event.channel.private?
      event.channel.send_embed error_embed(
        error: 'This command can only be used in servers!',
        footer: "Command: `#{command_run}`"
      )
      break
    end

    # If the user is a bot and the command is set to not pass bots
    # OR the user is a bot and the global config is to not parse bots...
    # ...then abort :3
    if event.user.bot_account? && \
       (chosen_command[:parse_bots] == false || @config[:parse_bots] == false)
      # Abort!
      break
    end

    # If the config is setup to show typing messages, then do so.
    event.channel.start_typing if chosen_command[:typing]

    # Our arguments are the message's contents, minus the activator.
    args = message_content
    args.slice! chosen_activator
    args = args.split

    no_permission = false

    chosen_command[:required_permissions]&.each do |x|
      if event.user.on(event.server).permission?(x, event.channel) \
        || (chosen_command[:owner_override] && @config[:owners].include?(event.user.id))
        next
      end

      event.channel.send_embed '', error_embed(
        error: "You don't have permission for that!\nPermission required: `#{x}`",
        footer: "Command: `#{command_run}`"
      )
      no_permission = true
      break
    end

    next if no_permission

    # If the command is set to owners only and the user is not the owner,
    # show an error and abort.
    puts "[DEBUG] Command being processed: '#{chosen_command}'" if @debug_mode == true
    puts "[DEBUG] Owners only? #{chosen_command[:owners_only]}" if @debug_mode == true
    if chosen_command[:owners_only] && !owner?(event.user.id)
      event.channel.send_embed '', error_embed(
        error: "You don't have permission for that!\n"\
               'Only owners are allowed to access this command.',
        footer: "Command: `#{command_run}`"
      )
      next
    end

    # Run the command code!
    # TODO: determine a good method to log other errors as made via the command.
    # Without, we will simply log to console.
    chosen_command[:code].call(event, args, message_content)

    # All done here.
    puts "Finished!! Executed command: #{chosen_activator}" if @debug_mode == true
    next
  end
end

Instance Attribute Details

#botObject

Needed to run the bot, or create custom events.



10
11
12
# File 'lib/commandrb.rb', line 10

def bot
  @bot
end

#commandsObject

Can manually manipulate commands using this.



13
14
15
# File 'lib/commandrb.rb', line 13

def commands
  @commands
end

#configObject

Be able to adjust the config on the fly.



7
8
9
# File 'lib/commandrb.rb', line 7

def config
  @config
end

#prefixesObject

Lets you change global prefixes while the bot is running (Not recommended!)



16
17
18
# File 'lib/commandrb.rb', line 16

def prefixes
  @prefixes
end

Instance Method Details

#add_command(name, attributes = {}) ⇒ Object



18
19
20
# File 'lib/commandrb.rb', line 18

def add_command(name, attributes = {})
  @commands[name.to_sym] = attributes
end

#code_embed(error: nil, footer: nil, colour: nil, color: nil) ⇒ Object

Generates a usable error embed with defaults, and a formatted error.



40
41
42
43
44
45
46
47
# File 'lib/helper.rb', line 40

def code_embed(error: nil, footer: nil, colour: nil, color: nil)
  raise 'Invalid arguments for Helper.code_embed!' if error.nil? || footer.nil?

  # Format to have a code block with formatting.
  error = "```ruby\n#{error}```"

  error_embed(error: error, footer: footer, colour: colour, color: color)
end

#error_embed(error: nil, footer: nil, colour: nil, color: nil) ⇒ Object

Generates a usable error embed with defaults.



27
28
29
30
31
32
33
34
35
36
37
# File 'lib/helper.rb', line 27

def error_embed(error: nil, footer: nil, colour: nil, color: nil)
  raise 'Invalid arguments for Helper.error_embed!' if error.nil? || footer.nil?

  colour = 0xFA0E30 if color.nil? && colour.nil?
  Discordrb::Webhooks::Embed.new(
    title: '❌ An error has occurred!',
    description: error,
    colour: colour || color,
    footer: Discordrb::Webhooks::EmbedFooter.new(text: footer)
  )
end

#owner?(id) ⇒ Boolean Also known as: is_owner?

By defining this separately, we allow you to overwrite it and use your own owner list. Your checks will instead be run by commandrb and allow you to use :owner_only as normal.

Returns:

  • (Boolean)


33
34
35
# File 'lib/commandrb.rb', line 33

def owner?(id)
  @config[:owners].include?(id)
end

#remove_command(name) ⇒ Object



22
23
24
25
26
27
28
29
# File 'lib/commandrb.rb', line 22

def remove_command(name)
  begin
    @commands.delete(name)
  rescue StandardError
    return false
  end
  true
end

#user_parse(context) ⇒ Object

Utilizes several methods to attempt to determine a user.



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/helper.rb', line 5

def user_parse(context)
  # Can't do anything if there's nothing to begin with.
  return nil if context.nil?

  # Catches cases such as "0": obviously invalid, attempted nonetheless.
  context = context.to_s

  # If it's an ID.
  id_check = bot.user(context)
  return id_check unless id_check.nil?

  # If it's a mention!
  matches = /<@!?(\d+)>/.match(context)
  return bot.user(matches[1]) unless matches.nil?

  # Might be a username...
  return bot.find_user(context)[0] unless bot.find_user(context).nil?

  nil
end