discordrb 3.4.3 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +44 -18
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -1
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -1
  5. data/.github/workflows/codeql.yml +65 -0
  6. data/.markdownlint.json +4 -0
  7. data/.rubocop.yml +8 -2
  8. data/CHANGELOG.md +390 -225
  9. data/LICENSE.txt +1 -1
  10. data/README.md +37 -25
  11. data/discordrb-webhooks.gemspec +4 -1
  12. data/discordrb.gemspec +9 -6
  13. data/lib/discordrb/api/application.rb +202 -0
  14. data/lib/discordrb/api/channel.rb +177 -11
  15. data/lib/discordrb/api/interaction.rb +54 -0
  16. data/lib/discordrb/api/invite.rb +2 -2
  17. data/lib/discordrb/api/server.rb +40 -19
  18. data/lib/discordrb/api/user.rb +8 -3
  19. data/lib/discordrb/api/webhook.rb +57 -0
  20. data/lib/discordrb/api.rb +19 -5
  21. data/lib/discordrb/bot.rb +317 -32
  22. data/lib/discordrb/cache.rb +27 -22
  23. data/lib/discordrb/commands/command_bot.rb +6 -4
  24. data/lib/discordrb/commands/container.rb +1 -1
  25. data/lib/discordrb/commands/parser.rb +2 -2
  26. data/lib/discordrb/commands/rate_limiter.rb +1 -1
  27. data/lib/discordrb/container.rb +132 -3
  28. data/lib/discordrb/data/attachment.rb +15 -0
  29. data/lib/discordrb/data/audit_logs.rb +3 -3
  30. data/lib/discordrb/data/channel.rb +167 -23
  31. data/lib/discordrb/data/component.rb +229 -0
  32. data/lib/discordrb/data/integration.rb +42 -3
  33. data/lib/discordrb/data/interaction.rb +800 -0
  34. data/lib/discordrb/data/invite.rb +1 -1
  35. data/lib/discordrb/data/member.rb +108 -33
  36. data/lib/discordrb/data/message.rb +99 -19
  37. data/lib/discordrb/data/overwrite.rb +13 -7
  38. data/lib/discordrb/data/role.rb +58 -1
  39. data/lib/discordrb/data/server.rb +82 -80
  40. data/lib/discordrb/data/user.rb +69 -9
  41. data/lib/discordrb/data/webhook.rb +97 -4
  42. data/lib/discordrb/data.rb +3 -0
  43. data/lib/discordrb/errors.rb +44 -3
  44. data/lib/discordrb/events/channels.rb +1 -1
  45. data/lib/discordrb/events/interactions.rb +482 -0
  46. data/lib/discordrb/events/message.rb +9 -6
  47. data/lib/discordrb/events/presence.rb +21 -14
  48. data/lib/discordrb/events/reactions.rb +0 -1
  49. data/lib/discordrb/events/threads.rb +96 -0
  50. data/lib/discordrb/gateway.rb +30 -17
  51. data/lib/discordrb/permissions.rb +59 -34
  52. data/lib/discordrb/version.rb +1 -1
  53. data/lib/discordrb/voice/encoder.rb +2 -2
  54. data/lib/discordrb/voice/network.rb +18 -7
  55. data/lib/discordrb/voice/sodium.rb +3 -1
  56. data/lib/discordrb/voice/voice_bot.rb +3 -3
  57. data/lib/discordrb/webhooks.rb +2 -0
  58. data/lib/discordrb.rb +37 -4
  59. metadata +48 -14
  60. data/.codeclimate.yml +0 -16
  61. data/.travis.yml +0 -32
  62. data/bin/travis_build_docs.sh +0 -17
@@ -70,7 +70,9 @@ module Discordrb::Commands
70
70
  # @option attributes [String] :quote_end Character that should end a quoted string (see
71
71
  # :advanced_functionality). Default is '"' or the same as :quote_start. Set to an empty string to disable.
72
72
  # @option attributes [true, false] :ignore_bots Whether the bot should ignore bot accounts or not. Default is false.
73
- def initialize(attributes = {})
73
+ def initialize(**attributes)
74
+ # TODO: This needs to be revisited. undefined attributes are treated
75
+ # as explicitly passed nils.
74
76
  super(
75
77
  log_mode: attributes[:log_mode],
76
78
  token: attributes[:token],
@@ -85,7 +87,7 @@ module Discordrb::Commands
85
87
  redact_token: attributes.key?(:redact_token) ? attributes[:redact_token] : true,
86
88
  ignore_bots: attributes[:ignore_bots],
87
89
  compress_mode: attributes[:compress_mode],
88
- intents: attributes[:intents]
90
+ intents: attributes[:intents] || :all
89
91
  )
90
92
 
91
93
  @prefix = attributes[:prefix]
@@ -335,7 +337,7 @@ module Discordrb::Commands
335
337
  return nil if chain.empty?
336
338
 
337
339
  args = chain.split(' ')
338
- execute_command(args[0].to_sym, event, args[1..-1])
340
+ execute_command(args[0].to_sym, event, args[1..])
339
341
  end
340
342
 
341
343
  # Sets the permission level of a user
@@ -443,7 +445,7 @@ module Discordrb::Commands
443
445
  def standard_prefix_trigger(message, prefix)
444
446
  return nil unless message.start_with? prefix
445
447
 
446
- message[prefix.length..-1]
448
+ message[prefix.length..]
447
449
  end
448
450
 
449
451
  def required_permissions?(member, required, channel = nil)
@@ -86,7 +86,7 @@ module Discordrb::Commands
86
86
  # Adds all commands from another container into this one. Existing commands will be overwritten.
87
87
  # @param container [Module] A module that `extend`s {CommandContainer} from which the commands will be added.
88
88
  def include_commands(container)
89
- handlers = container.instance_variable_get '@commands'
89
+ handlers = container.instance_variable_get :@commands
90
90
  return unless handlers
91
91
 
92
92
  @commands ||= {}
@@ -246,7 +246,7 @@ module Discordrb::Commands
246
246
 
247
247
  first_space = command.index ' '
248
248
  command_name = first_space ? command[0..first_space - 1] : command
249
- arguments = first_space ? command[first_space + 1..-1] : ''
249
+ arguments = first_space ? command[first_space + 1..] : ''
250
250
 
251
251
  # Append a previous sign if none is present
252
252
  arguments += @attributes[:previous] unless arguments.include? @attributes[:previous]
@@ -318,7 +318,7 @@ module Discordrb::Commands
318
318
  arg.split ' '
319
319
  end
320
320
 
321
- chain = chain[chain_args_index + 1..-1]
321
+ chain = chain[chain_args_index + 1..]
322
322
  end
323
323
 
324
324
  [chain_args, chain]
@@ -125,7 +125,7 @@ module Discordrb::Commands
125
125
  # Adds all the buckets from another RateLimiter onto this one.
126
126
  # @param limiter [Module] Another {RateLimiter} module
127
127
  def include_buckets(limiter)
128
- buckets = limiter.instance_variable_get('@buckets') || {}
128
+ buckets = limiter.instance_variable_get(:@buckets) || {}
129
129
  @buckets ||= {}
130
130
  @buckets.merge! buckets
131
131
  end
@@ -13,6 +13,7 @@ require 'discordrb/events/guilds'
13
13
  require 'discordrb/events/await'
14
14
  require 'discordrb/events/bans'
15
15
  require 'discordrb/events/reactions'
16
+ require 'discordrb/events/interactions'
16
17
 
17
18
  require 'discordrb/await'
18
19
 
@@ -522,6 +523,118 @@ module Discordrb
522
523
  register_event(InviteDeleteEvent, attributes, block)
523
524
  end
524
525
 
526
+ # This **event** is raised whenever an interaction event is received.
527
+ # @param attributes [Hash] The event's attributes.
528
+ # @option attributes [Integer, Symbol, String] :type The interaction type, can be the integer value or the name
529
+ # of the key in {Discordrb::Interaction::TYPES}.
530
+ # @option attributes [String, Integer, Server, nil] :server The server where this event was created. `nil` for DM channels.
531
+ # @option attributes [String, Integer, Channel] :channel The channel where this event was created.
532
+ # @option attributes [String, Integer, User] :user The user that triggered this event.
533
+ # @yield The block is executed when the event is raised.
534
+ # @yieldparam event [InteractionCreateEvent] The event that was raised.
535
+ # @return [InteractionCreateEventHandler] The event handler that was registered.
536
+ def interaction_create(attributes = {}, &block)
537
+ register_event(InteractionCreateEvent, attributes, block)
538
+ end
539
+
540
+ # This **event** is raised whenever an application command (slash command) is executed.
541
+ # @param name [Symbol] The name of the application command this handler is for.
542
+ # @param attributes [Hash] The event's attributes.
543
+ # @yield The block is executed when the event is raised.
544
+ # @yieldparam event [ApplicationCommandEvent] The event that was raised.
545
+ # @return [ApplicationCommandEventHandler] The event handler that was registered.
546
+ def application_command(name, attributes = {}, &block)
547
+ @application_commands ||= {}
548
+
549
+ unless block
550
+ @application_commands[name] ||= ApplicationCommandEventHandler.new(attributes, nil)
551
+ return @application_commands[name]
552
+ end
553
+
554
+ @application_commands[name] = ApplicationCommandEventHandler.new(attributes, block)
555
+ end
556
+
557
+ # This **event** is raised whenever an button interaction is created.
558
+ # @param attributes [Hash] The event's attributes.
559
+ # @option attributes [String, Regexp] :custom_id A custom_id to match against.
560
+ # @option attributes [String, Integer, Message] :message The message to filter for.
561
+ # @yield The block is executed when the event is raised.
562
+ # @yieldparam event [ButtonEvent] The event that was raised.
563
+ # @return [ButtonEventHandler] The event handler that was registered.
564
+ def button(attributes = {}, &block)
565
+ register_event(ButtonEvent, attributes, block)
566
+ end
567
+
568
+ # This **event** is raised whenever an select string interaction is created.
569
+ # @param attributes [Hash] The event's attributes.
570
+ # @option attributes [String, Regexp] :custom_id A custom_id to match against.
571
+ # @option attributes [String, Integer, Message] :message The message to filter for.
572
+ # @yield The block is executed when the event is raised.
573
+ # @yieldparam event [StringSelectEvent] The event that was raised.
574
+ # @return [StringSelectEventHandler] The event handler that was registered.
575
+ def string_select(attributes = {}, &block)
576
+ register_event(StringSelectEvent, attributes, block)
577
+ end
578
+
579
+ alias_method :select_menu, :string_select
580
+
581
+ # This **event** is raised whenever a modal is submitted.
582
+ # @param attributes [Hash] The event's attributes.
583
+ # @option attributes [String, Regexp] :custom_id A custom_id to match against.
584
+ # @option attributes [String, Integer, Message] :message The message to filter for.
585
+ # @option attributes [String, Integer, Server, nil] :server The server where this event was created. `nil` for DM channels.
586
+ # @option attributes [String, Integer, Channel] :channel The channel where this event was created.
587
+ # @option attributes [String, Integer, User] :user The user that triggered this event. # @yield The block is executed when the event is raised.
588
+ # @yieldparam event [ModalSubmitEvent] The event that was raised.
589
+ # @return [ModalSubmitEventHandler] The event handler that was registered.
590
+ def modal_submit(attributes = {}, &block)
591
+ register_event(ModalSubmitEvent, attributes, block)
592
+ end
593
+
594
+ # This **event** is raised whenever an select user interaction is created.
595
+ # @param attributes [Hash] The event's attributes.
596
+ # @option attributes [String, Regexp] :custom_id A custom_id to match against.
597
+ # @option attributes [String, Integer, Message] :message The message to filter for.
598
+ # @yield The block is executed when the event is raised.
599
+ # @yieldparam event [UserSelectEvent] The event that was raised.
600
+ # @return [UserSelectEventHandler] The event handler that was registered.
601
+ def user_select(attributes = {}, &block)
602
+ register_event(UserSelectEvent, attributes, block)
603
+ end
604
+
605
+ # This **event** is raised whenever an select role interaction is created.
606
+ # @param attributes [Hash] The event's attributes.
607
+ # @option attributes [String, Regexp] :custom_id A custom_id to match against.
608
+ # @option attributes [String, Integer, Message] :message The message to filter for.
609
+ # @yield The block is executed when the event is raised.
610
+ # @yieldparam event [RoleSelectEvent] The event that was raised.
611
+ # @return [RoleSelectEventHandler] The event handler that was registered.
612
+ def role_select(attributes = {}, &block)
613
+ register_event(RoleSelectEvent, attributes, block)
614
+ end
615
+
616
+ # This **event** is raised whenever an select mentionable interaction is created.
617
+ # @param attributes [Hash] The event's attributes.
618
+ # @option attributes [String, Regexp] :custom_id A custom_id to match against.
619
+ # @option attributes [String, Integer, Message] :message The message to filter for.
620
+ # @yield The block is executed when the event is raised.
621
+ # @yieldparam event [MentionableSelectEvent] The event that was raised.
622
+ # @return [MentionableSelectEventHandler] The event handler that was registered.
623
+ def mentionable_select(attributes = {}, &block)
624
+ register_event(MentionableSelectEvent, attributes, block)
625
+ end
626
+
627
+ # This **event** is raised whenever an select channel interaction is created.
628
+ # @param attributes [Hash] The event's attributes.
629
+ # @option attributes [String, Regexp] :custom_id A custom_id to match against.
630
+ # @option attributes [String, Integer, Message] :message The message to filter for.
631
+ # @yield The block is executed when the event is raised.
632
+ # @yieldparam event [ChannelSelectEvent] The event that was raised.
633
+ # @return [ChannelSelectEventHandler] The event handler that was registered.
634
+ def channel_select(attributes = {}, &block)
635
+ register_event(ChannelSelectEvent, attributes, block)
636
+ end
637
+
525
638
  # This **event** is raised for every dispatch received over the gateway, whether supported by discordrb or not.
526
639
  # @param attributes [Hash] The event's attributes.
527
640
  # @option attributes [String, Symbol, Regexp] :type Matches the event type of the dispatch.
@@ -552,9 +665,16 @@ module Discordrb
552
665
  @event_handlers[clazz].delete(handler)
553
666
  end
554
667
 
668
+ # Remove an application command handler
669
+ # @param name [String, Symbol] The name of the command handler to remove.
670
+ def remove_application_command_handler(name)
671
+ @application_commands.delete(name)
672
+ end
673
+
555
674
  # Removes all events from this event handler.
556
675
  def clear!
557
676
  @event_handlers&.clear
677
+ @application_commands&.clear
558
678
  end
559
679
 
560
680
  # Adds an event handler to this container. Usually, it's more expressive to just use one of the shorthand adder
@@ -570,11 +690,19 @@ module Discordrb
570
690
  # Adds all event handlers from another container into this one. Existing event handlers will be overwritten.
571
691
  # @param container [Module] A module that `extend`s {EventContainer} from which the handlers will be added.
572
692
  def include_events(container)
573
- handlers = container.instance_variable_get '@event_handlers'
574
- return unless handlers
693
+ application_command_handlers = container.instance_variable_get(:@application_commands)
694
+ handlers = container.instance_variable_get :@event_handlers
695
+ return unless handlers || application_command_handlers
575
696
 
576
697
  @event_handlers ||= {}
577
- @event_handlers.merge!(handlers) { |_, old, new| old + new }
698
+ @event_handlers.merge!(handlers || {}) { |_, old, new| old + new }
699
+
700
+ @application_commands ||= {}
701
+
702
+ @application_commands.merge!(application_command_handlers || {}) do |_, old, new|
703
+ old.subcommands.merge!(new.subcommands)
704
+ old
705
+ end
578
706
  end
579
707
 
580
708
  alias_method :include!, :include_events
@@ -612,6 +740,7 @@ module Discordrb
612
740
 
613
741
  include Discordrb::Events
614
742
 
743
+ # @return [EventHandler]
615
744
  def register_event(clazz, attributes, block)
616
745
  handler = EventContainer.handler_class(clazz).new(attributes, block)
617
746
 
@@ -27,6 +27,16 @@ module Discordrb
27
27
  # @return [Integer, nil] the height of an image file, in pixels, or `nil` if the file is not an image.
28
28
  attr_reader :height
29
29
 
30
+ # @return [String, nil] the attachment's description.
31
+ attr_reader :description
32
+
33
+ # @return [String, nil] the attachment's media type.
34
+ attr_reader :content_type
35
+
36
+ # @return [true, false] whether this attachment is ephemeral.
37
+ attr_reader :ephemeral
38
+ alias_method :ephemeral?, :ephemeral
39
+
30
40
  # @!visibility private
31
41
  def initialize(data, message, bot)
32
42
  @bot = bot
@@ -41,6 +51,11 @@ module Discordrb
41
51
 
42
52
  @width = data['width']
43
53
  @height = data['height']
54
+
55
+ @description = data['description']
56
+ @content_type = data['content_type']
57
+
58
+ @ephemeral = data['ephemeral']
44
59
  end
45
60
 
46
61
  # @return [true, false] whether this file is an image file.
@@ -177,7 +177,7 @@ module Discordrb
177
177
 
178
178
  # The inspect method is overwritten to give more useful output
179
179
  def inspect
180
- "<AuditLogs::Entry id=#{@id} action=#{@action} reason=#{@reason} action_type=#{@action_type} target_type=#{@target_type} count=#{@count} days=#{@days} members_removed=#{@members_removed}>"
180
+ "<AuditLogs::Entry id=#{@id} key=#{@key} action=#{@action} reason=#{@reason} action_type=#{@action_type} target_type=#{@target_type} count=#{@count} days=#{@days} members_removed=#{@members_removed}>"
181
181
  end
182
182
 
183
183
  # Process action changes
@@ -219,8 +219,8 @@ module Discordrb
219
219
  @old = Permissions.new(@old) if @old && @key == 'permissions'
220
220
  @new = Permissions.new(@new) if @new && @key == 'permissions'
221
221
 
222
- @old = @old.map { |o| Overwrite.new(o['id'], type: o['type'].to_sym, allow: o['allow'], deny: o['deny']) } if @old && @key == 'permission_overwrites'
223
- @new = @new.map { |o| Overwrite.new(o['id'], type: o['type'].to_sym, allow: o['allow'], deny: o['deny']) } if @new && @key == 'permission_overwrites'
222
+ @old = @old.map { |o| Overwrite.new(o['id'], type: o['type'], allow: o['allow'], deny: o['deny']) } if @old && @key == 'permission_overwrites'
223
+ @new = @new.map { |o| Overwrite.new(o['id'], type: o['type'], allow: o['allow'], deny: o['deny']) } if @new && @key == 'permission_overwrites'
224
224
  end
225
225
 
226
226
  # @return [Channel, nil] the channel that was previously used in the server widget. Only present if the key for this change is `widget_channel_id`.
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'discordrb/webhooks/view'
4
+ require 'time'
5
+
3
6
  module Discordrb
4
7
  # A Discord channel, including data like the topic
5
8
  class Channel
@@ -13,23 +16,28 @@ module Discordrb
13
16
  group: 3,
14
17
  category: 4,
15
18
  news: 5,
16
- store: 6
19
+ store: 6,
20
+ news_thread: 10,
21
+ public_thread: 11,
22
+ private_thread: 12,
23
+ stage_voice: 13,
24
+ directory: 14,
25
+ forum: 15
17
26
  }.freeze
18
27
 
19
28
  # @return [String] this channel's name.
20
29
  attr_reader :name
21
30
 
22
- # @return [Server, nil] the server this channel is on. If this channel is a PM channel, it will be nil.
23
- attr_reader :server
24
-
25
- # @return [Integer, nil] the ID of the parent channel, if this channel is inside a category
31
+ # @return [Integer, nil] the ID of the parent channel, if this channel is inside a category. If this channel is a
32
+ # thread, this is the text channel it is a child to.
26
33
  attr_reader :parent_id
27
34
 
28
35
  # @return [Integer] the type of this channel
29
36
  # @see TYPES
30
37
  attr_reader :type
31
38
 
32
- # @return [Integer, nil] the ID of the owner of the group channel or nil if this is not a group channel.
39
+ # @return [Integer, nil] the ID of the owner of the group channel or nil if this is not a group channel. If this
40
+ # channel is a thread, this is the member that started the thread.
33
41
  attr_reader :owner_id
34
42
 
35
43
  # @return [Array<Recipient>, nil] the array of recipients of the private messages, or nil if this is not a Private channel
@@ -56,6 +64,35 @@ module Discordrb
56
64
  attr_reader :rate_limit_per_user
57
65
  alias_method :slowmode_rate, :rate_limit_per_user
58
66
 
67
+ # @return [Integer, nil] An approximate count of messages sent in a thread. Stops counting at 50.
68
+ attr_reader :message_count
69
+
70
+ # @return [Integer, nil] An approximate count of members in a thread. Stops counting at 50.
71
+ attr_reader :member_count
72
+
73
+ # @return [true, false, nil] Whether or not this thread is archived.
74
+ attr_reader :archived
75
+
76
+ # @return [Integer, nil] How long after the last message before a thread is automatically archived.
77
+ attr_reader :auto_archive_duration
78
+
79
+ # @return [Time, nil] The timestamp of when this threads status last changed.
80
+ attr_reader :archive_timestamp
81
+
82
+ # @return [true, false, nil] Whether this thread is locked or not.
83
+ attr_reader :locked
84
+ alias_method :locked?, :locked
85
+
86
+ # @return [Time, nil] When the current user joined this thread.
87
+ attr_reader :join_timestamp
88
+
89
+ # @return [Integer, nil] Member flags for this thread, used for notifications.
90
+ attr_reader :member_flags
91
+
92
+ # @return [true, false] For private threads, determines whether non-moderators can add other non-moderators to
93
+ # a thread.
94
+ attr_reader :invitable
95
+
59
96
  # @return [true, false] whether or not this channel is a PM or group channel.
60
97
  def private?
61
98
  pm? || group?
@@ -99,15 +136,44 @@ module Discordrb
99
136
  end
100
137
  else
101
138
  @name = data['name']
102
- @server = server || bot.server(data['guild_id'].to_i)
139
+ @server_id = server&.id || data['guild_id'].to_i
140
+ @server = server
103
141
  end
104
142
 
105
143
  @nsfw = data['nsfw'] || false
106
144
  @rate_limit_per_user = data['rate_limit_per_user'] || 0
145
+ @message_count = data['message_count']
146
+ @member_count = data['member_count']
147
+
148
+ if (metadata = data['thread_metadata'])
149
+ @archived = metadata['archived']
150
+ @auto_archive_duration = metadata['auto_archive_duration']
151
+ @archive_timestamp = Time.iso8601(metadata['archive_timestamp'])
152
+ @locked = metadata['locked']
153
+ @invitable = metadata['invitable']
154
+ end
155
+
156
+ if (member = data['member'])
157
+ @member_join = Time.iso8601(member['join_timestamp'])
158
+ @member_flags = member['flags']
159
+ end
107
160
 
108
161
  process_permission_overwrites(data['permission_overwrites'])
109
162
  end
110
163
 
164
+ # @return [Server, nil] the server this channel is on. If this channel is a PM channel, it will be nil.
165
+ # @raise [Discordrb::Errors::NoPermission] This can happen when receiving interactions for servers in which the bot is not
166
+ # authorized with the `bot` scope.
167
+ def server
168
+ return @server if @server
169
+ return nil if private?
170
+
171
+ @server = @bot.server(@server_id)
172
+ raise Discordrb::Errors::NoPermission, 'The bot does not have access to this server' unless @server
173
+
174
+ @server
175
+ end
176
+
111
177
  # @return [true, false] whether or not this channel is a text channel
112
178
  def text?
113
179
  @type.zero?
@@ -143,6 +209,26 @@ module Discordrb
143
209
  @type == 6
144
210
  end
145
211
 
212
+ # @return [true, false] whether or not this channel is a news thread.
213
+ def news_thread?
214
+ @type == 10
215
+ end
216
+
217
+ # @return [true, false] whether or not this channel is a public thread.
218
+ def public_thread?
219
+ @type == 11
220
+ end
221
+
222
+ # @return [true, false] whether or not this channel is a private thread.
223
+ def private_thread?
224
+ @type == 12
225
+ end
226
+
227
+ # @return [true, false] whether or not this channel is a thread.
228
+ def thread?
229
+ news_thread? || public_thread? || private_thread?
230
+ end
231
+
146
232
  # @return [Channel, nil] the category channel, if this channel is in a category
147
233
  def category
148
234
  @bot.channel(@parent_id) if @parent_id
@@ -199,7 +285,7 @@ module Discordrb
199
285
  ids = if parent
200
286
  parent.children
201
287
  else
202
- @server.channels.reject(&:parent_id).select { |c| c.type == @type }
288
+ server.channels.reject(&:parent_id).select { |c| c.type == @type }
203
289
  end.sort_by(&:position).map(&:id)
204
290
 
205
291
  # Move our channel ID after the target ID by deleting it,
@@ -225,7 +311,7 @@ module Discordrb
225
311
  move_argument << hash
226
312
  end
227
313
 
228
- API::Server.update_channel_positions(@bot.token, @server.id, move_argument)
314
+ API::Server.update_channel_positions(@bot.token, @server_id, move_argument)
229
315
  end
230
316
 
231
317
  # Sets whether this channel is NSFW
@@ -262,9 +348,9 @@ module Discordrb
262
348
 
263
349
  # Sets the amount of time (in seconds) users have to wait in between sending messages.
264
350
  # @param rate [Integer]
265
- # @raise [ArgumentError] if value isn't between 0 and 120
351
+ # @raise [ArgumentError] if value isn't between 0 and 21600
266
352
  def rate_limit_per_user=(rate)
267
- raise ArgumentError, 'rate_limit_per_user must be between 0 and 120' unless rate.between?(0, 120)
353
+ raise ArgumentError, 'rate_limit_per_user must be between 0 and 21600' unless rate.between?(0, 21_600)
268
354
 
269
355
  update_channel_data(rate_limit_per_user: rate)
270
356
  end
@@ -341,9 +427,10 @@ module Discordrb
341
427
  # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
342
428
  # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
343
429
  # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
430
+ # @param components [View, Array<Hash>] Interaction components to associate with this message.
344
431
  # @return [Message] the message that was sent.
345
- def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil)
346
- @bot.send_message(@id, content, tts, embed, attachments, allowed_mentions, message_reference)
432
+ def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
433
+ @bot.send_message(@id, content, tts, embed, attachments, allowed_mentions, message_reference, components)
347
434
  end
348
435
 
349
436
  alias_method :send, :send_message
@@ -356,8 +443,9 @@ module Discordrb
356
443
  # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
357
444
  # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
358
445
  # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
359
- def send_temporary_message(content, timeout, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil)
360
- @bot.send_temporary_message(@id, content, timeout, tts, embed, attachments, allowed_mentions, message_reference)
446
+ # @param components [View, Array<Hash>] Interaction components to associate with this message.
447
+ def send_temporary_message(content, timeout, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
448
+ @bot.send_temporary_message(@id, content, timeout, tts, embed, attachments, allowed_mentions, message_reference, components)
361
449
  end
362
450
 
363
451
  # Convenience method to send a message with an embed.
@@ -372,13 +460,17 @@ module Discordrb
372
460
  # @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
373
461
  # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
374
462
  # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
463
+ # @param components [View, Array<Hash>] Interaction components to associate with this message.
375
464
  # @yield [embed] Yields the embed to allow for easy building inside a block.
376
465
  # @yieldparam embed [Discordrb::Webhooks::Embed] The embed from the parameters, or a new one.
377
466
  # @return [Message] The resulting message.
378
- def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil)
467
+ def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil, components = nil)
379
468
  embed ||= Discordrb::Webhooks::Embed.new
380
- yield(embed) if block_given?
381
- send_message(message, tts, embed, attachments, allowed_mentions, message_reference)
469
+ view = Discordrb::Webhooks::View.new
470
+
471
+ yield(embed, view) if block_given?
472
+
473
+ send_message(message, tts, embed, attachments, allowed_mentions, message_reference, components || view.to_a)
382
474
  end
383
475
 
384
476
  # Sends multiple messages to a channel
@@ -518,9 +610,9 @@ module Discordrb
518
610
  # @return [Array<Member>] the users in this channel
519
611
  def users
520
612
  if text?
521
- @server.online_members(include_idle: true).select { |u| u.can_read_messages? self }
613
+ server.online_members(include_idle: true).select { |u| u.can_read_messages? self }
522
614
  elsif voice?
523
- @server.voice_states.map { |id, voice_state| @server.member(id) if !voice_state.voice_channel.nil? && voice_state.voice_channel.id == @id }.compact
615
+ server.voice_states.filter_map { |id, voice_state| server.member(id) if !voice_state.voice_channel.nil? && voice_state.voice_channel.id == @id }
524
616
  end
525
617
  end
526
618
 
@@ -554,9 +646,11 @@ module Discordrb
554
646
  # @param message_id [Integer] The ID of the message to retrieve.
555
647
  # @return [Message, nil] the retrieved message, or `nil` if it couldn't be found.
556
648
  def load_message(message_id)
649
+ raise ArgumentError, 'message_id cannot be nil' if message_id.nil?
650
+
557
651
  response = API::Channel.message(@bot.token, @id, message_id)
558
652
  Message.new(JSON.parse(response), @bot)
559
- rescue RestClient::ResourceNotFound
653
+ rescue Discordrb::Errors::UnknownMessage
560
654
  nil
561
655
  end
562
656
 
@@ -742,9 +836,59 @@ module Discordrb
742
836
  invites.map { |invite_data| Invite.new(invite_data, @bot) }
743
837
  end
744
838
 
839
+ # Start a thread.
840
+ # @param name [String] The name of the thread.
841
+ # @param auto_archive_duration [60, 1440, 4320, 10080] How long before a thread is automatically
842
+ # archived.
843
+ # @param message [Message, Integer, String] The message to reference when starting this thread.
844
+ # @param type [Symbol, Integer] The type of thread to create. Can be a key from {TYPES} or the value.
845
+ # @return [Channel]
846
+ def start_thread(name, auto_archive_duration, message: nil, type: 11)
847
+ message_id = message&.id || message
848
+ type = TYPES[type] || type
849
+
850
+ data = if message
851
+ API::Channel.start_thread_with_message(@bot.token, @id, message_id, name, auto_archive_duration)
852
+ else
853
+ API::Channel.start_thread_without_message(@bot.token, @id, name, auto_archive_duration, type)
854
+ end
855
+
856
+ Channel.new(JSON.parse(data), @bot, @server)
857
+ end
858
+
859
+ # @!group Threads
860
+
861
+ # Join this thread.
862
+ def join_thread
863
+ @bot.join_thread(@id)
864
+ end
865
+
866
+ # Leave this thread
867
+ def leave_thread
868
+ @bot.leave_thread(@id)
869
+ end
870
+
871
+ # Members in the thread.
872
+ def members
873
+ @bot.thread_members[@id].collect { |id| @server_id ? @bot.member(@server_id, id) : @bot.user(id) }
874
+ end
875
+
876
+ # Add a member to the thread
877
+ # @param member [Member, Integer, String] The member, or ID of the member, to add to this thread.
878
+ def add_member(member)
879
+ @bot.add_thread_member(@id, member)
880
+ end
881
+
882
+ # @param member [Member, Integer, String] The member, or ID of the member, to remove from a thread.
883
+ def remove_member(member)
884
+ @bot.remove_thread_member(@id, member)
885
+ end
886
+
887
+ # @!endgroup
888
+
745
889
  # The default `inspect` method is overwritten to give more useful output.
746
890
  def inspect
747
- "<Channel name=#{@name} id=#{@id} topic=\"#{@topic}\" type=#{@type} position=#{@position} server=#{@server}>"
891
+ "<Channel name=#{@name} id=#{@id} topic=\"#{@topic}\" type=#{@type} position=#{@position} server=#{@server || @server_id}>"
748
892
  end
749
893
 
750
894
  # Adds a recipient to a group channel.
@@ -790,7 +934,7 @@ module Discordrb
790
934
 
791
935
  # @return [String] a URL that a user can use to navigate to this channel in the client
792
936
  def link
793
- "https://discord.com/channels/#{@server&.id || '@me'}/#{@channel.id}"
937
+ "https://discord.com/channels/#{@server_id || '@me'}/#{@channel.id}"
794
938
  end
795
939
 
796
940
  alias_method :jump_link, :link