discordrb 3.4.3 → 3.6.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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +13 -0
  3. data/.devcontainer/devcontainer.json +29 -0
  4. data/.devcontainer/postcreate.sh +4 -0
  5. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -1
  6. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -1
  7. data/.github/workflows/ci.yml +78 -0
  8. data/.github/workflows/codeql.yml +65 -0
  9. data/.github/workflows/deploy.yml +54 -0
  10. data/.github/workflows/release.yml +45 -0
  11. data/.markdownlint.json +4 -0
  12. data/.rubocop.yml +58 -2
  13. data/CHANGELOG.md +485 -225
  14. data/LICENSE.txt +1 -1
  15. data/README.md +38 -26
  16. data/discordrb-webhooks.gemspec +4 -1
  17. data/discordrb.gemspec +18 -10
  18. data/lib/discordrb/api/application.rb +278 -0
  19. data/lib/discordrb/api/channel.rb +222 -18
  20. data/lib/discordrb/api/interaction.rb +63 -0
  21. data/lib/discordrb/api/invite.rb +2 -2
  22. data/lib/discordrb/api/server.rb +123 -66
  23. data/lib/discordrb/api/user.rb +20 -5
  24. data/lib/discordrb/api/webhook.rb +72 -0
  25. data/lib/discordrb/api.rb +35 -25
  26. data/lib/discordrb/bot.rb +437 -66
  27. data/lib/discordrb/cache.rb +41 -22
  28. data/lib/discordrb/commands/command_bot.rb +13 -21
  29. data/lib/discordrb/commands/container.rb +1 -1
  30. data/lib/discordrb/commands/parser.rb +7 -7
  31. data/lib/discordrb/commands/rate_limiter.rb +1 -1
  32. data/lib/discordrb/container.rb +178 -3
  33. data/lib/discordrb/data/activity.rb +1 -1
  34. data/lib/discordrb/data/application.rb +1 -0
  35. data/lib/discordrb/data/attachment.rb +38 -3
  36. data/lib/discordrb/data/audit_logs.rb +3 -3
  37. data/lib/discordrb/data/avatar_decoration.rb +26 -0
  38. data/lib/discordrb/data/call.rb +22 -0
  39. data/lib/discordrb/data/channel.rb +299 -30
  40. data/lib/discordrb/data/collectibles.rb +45 -0
  41. data/lib/discordrb/data/component.rb +229 -0
  42. data/lib/discordrb/data/embed.rb +10 -3
  43. data/lib/discordrb/data/emoji.rb +20 -1
  44. data/lib/discordrb/data/integration.rb +45 -3
  45. data/lib/discordrb/data/interaction.rb +937 -0
  46. data/lib/discordrb/data/invite.rb +1 -1
  47. data/lib/discordrb/data/member.rb +236 -44
  48. data/lib/discordrb/data/message.rb +278 -51
  49. data/lib/discordrb/data/overwrite.rb +15 -7
  50. data/lib/discordrb/data/primary_server.rb +60 -0
  51. data/lib/discordrb/data/profile.rb +2 -7
  52. data/lib/discordrb/data/reaction.rb +2 -1
  53. data/lib/discordrb/data/recipient.rb +1 -1
  54. data/lib/discordrb/data/role.rb +204 -18
  55. data/lib/discordrb/data/server.rb +194 -118
  56. data/lib/discordrb/data/server_preview.rb +68 -0
  57. data/lib/discordrb/data/snapshot.rb +110 -0
  58. data/lib/discordrb/data/user.rb +132 -12
  59. data/lib/discordrb/data/voice_region.rb +1 -0
  60. data/lib/discordrb/data/webhook.rb +99 -9
  61. data/lib/discordrb/data.rb +9 -0
  62. data/lib/discordrb/errors.rb +47 -3
  63. data/lib/discordrb/events/await.rb +1 -1
  64. data/lib/discordrb/events/channels.rb +38 -1
  65. data/lib/discordrb/events/generic.rb +2 -0
  66. data/lib/discordrb/events/guilds.rb +6 -1
  67. data/lib/discordrb/events/interactions.rb +575 -0
  68. data/lib/discordrb/events/invites.rb +2 -0
  69. data/lib/discordrb/events/members.rb +19 -2
  70. data/lib/discordrb/events/message.rb +42 -8
  71. data/lib/discordrb/events/presence.rb +23 -14
  72. data/lib/discordrb/events/raw.rb +1 -0
  73. data/lib/discordrb/events/reactions.rb +2 -1
  74. data/lib/discordrb/events/roles.rb +2 -0
  75. data/lib/discordrb/events/threads.rb +100 -0
  76. data/lib/discordrb/events/typing.rb +1 -0
  77. data/lib/discordrb/events/voice_server_update.rb +1 -0
  78. data/lib/discordrb/events/voice_state_update.rb +1 -0
  79. data/lib/discordrb/events/webhooks.rb +1 -0
  80. data/lib/discordrb/gateway.rb +57 -28
  81. data/lib/discordrb/paginator.rb +3 -3
  82. data/lib/discordrb/permissions.rb +71 -35
  83. data/lib/discordrb/version.rb +1 -1
  84. data/lib/discordrb/voice/encoder.rb +2 -2
  85. data/lib/discordrb/voice/network.rb +18 -7
  86. data/lib/discordrb/voice/sodium.rb +3 -1
  87. data/lib/discordrb/voice/voice_bot.rb +3 -3
  88. data/lib/discordrb/webhooks.rb +2 -0
  89. data/lib/discordrb/websocket.rb +0 -10
  90. data/lib/discordrb.rb +54 -5
  91. metadata +87 -25
  92. data/.circleci/config.yml +0 -126
  93. data/.codeclimate.yml +0 -16
  94. data/.travis.yml +0 -32
  95. data/bin/travis_build_docs.sh +0 -17
@@ -0,0 +1,229 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discordrb
4
+ # Components are interactable interfaces that can be attached to messages.
5
+ module Components
6
+ # @deprecated This alias will be removed in future releases.
7
+ class View < Webhooks::View
8
+ end
9
+
10
+ # @!visibility private
11
+ def self.from_data(data, bot)
12
+ case data['type']
13
+ when Webhooks::View::COMPONENT_TYPES[:action_row]
14
+ ActionRow.new(data, bot)
15
+ when Webhooks::View::COMPONENT_TYPES[:button]
16
+ Button.new(data, bot)
17
+ when Webhooks::View::COMPONENT_TYPES[:string_select]
18
+ SelectMenu.new(data, bot)
19
+ when Webhooks::Modal::COMPONENT_TYPES[:text_input]
20
+ TextInput.new(data, bot)
21
+ end
22
+ end
23
+
24
+ # Represents a row of components
25
+ class ActionRow
26
+ include Enumerable
27
+
28
+ # @return [Array<Button>]
29
+ attr_reader :components
30
+
31
+ # @!visibility private
32
+ def initialize(data, bot)
33
+ @bot = bot
34
+ @components = data['components'].map { |component_data| Components.from_data(component_data, @bot) }
35
+ end
36
+
37
+ # Iterate over each component in the row.
38
+ def each(&block)
39
+ @components.each(&block)
40
+ end
41
+
42
+ # Get all buttons in this row
43
+ # @return [Array<Button>]
44
+ def buttons
45
+ select { |component| component.is_a? Button }
46
+ end
47
+
48
+ # Get all buttons in this row
49
+ # @return [Array<Button>]
50
+ def text_inputs
51
+ select { |component| component.is_a? TextInput }
52
+ end
53
+
54
+ # @!visibility private
55
+ def to_a
56
+ @components
57
+ end
58
+ end
59
+
60
+ # An interactable button component.
61
+ class Button
62
+ # @return [String]
63
+ attr_reader :label
64
+
65
+ # @return [Integer]
66
+ attr_reader :style
67
+
68
+ # @return [String]
69
+ attr_reader :custom_id
70
+
71
+ # @return [true, false]
72
+ attr_reader :disabled
73
+
74
+ # @return [String, nil]
75
+ attr_reader :url
76
+
77
+ # @return [Emoji, nil]
78
+ attr_reader :emoji
79
+
80
+ # @!visibility private
81
+ def initialize(data, bot)
82
+ @bot = bot
83
+
84
+ @label = data['label']
85
+ @style = data['style']
86
+ @custom_id = data['custom_id']
87
+ @disabled = data['disabled']
88
+ @url = data['url']
89
+ @emoji = Emoji.new(data['emoji'], @bot) if data['emoji']
90
+ end
91
+
92
+ # @method primary?
93
+ # @return [true, false]
94
+ # @method secondary?
95
+ # @return [true, false]
96
+ # @method success?
97
+ # @return [true, false]
98
+ # @method danger?
99
+ # @return [true, false]
100
+ # @method link?
101
+ # @return [true, false]
102
+ Webhooks::View::BUTTON_STYLES.each do |name, value|
103
+ define_method("#{name}?") do
104
+ @style == value
105
+ end
106
+ end
107
+
108
+ # Await a button click
109
+ def await_click(key, **attributes, &block)
110
+ @bot.add_await(key, Discordrb::Events::ButtonEvent, { custom_id: @custom_id }.merge(attributes), &block)
111
+ end
112
+
113
+ # Await a button click, blocking.
114
+ def await_click!(**attributes, &block)
115
+ @bot.add_await!(Discordrb::Events::ButtonEvent, { custom_id: @custom_id }.merge(attributes), &block)
116
+ end
117
+ end
118
+
119
+ # An interactable select menu component.
120
+ class SelectMenu
121
+ # A select menu option.
122
+ class Option
123
+ # @return [String]
124
+ attr_reader :label
125
+
126
+ # @return [String]
127
+ attr_reader :value
128
+
129
+ # @return [String, nil]
130
+ attr_reader :description
131
+
132
+ # @return [Emoji, nil]
133
+ attr_reader :emoji
134
+
135
+ # @!visibility hidden
136
+ def initialize(data)
137
+ @label = data['label']
138
+ @value = data['value']
139
+ @description = data['description']
140
+ @emoji = Emoji.new(data['emoji'], @bot) if data['emoji']
141
+ end
142
+ end
143
+
144
+ # @return [String]
145
+ attr_reader :custom_id
146
+
147
+ # @return [Integer, nil]
148
+ attr_reader :max_values
149
+
150
+ # @return [Integer, nil]
151
+ attr_reader :min_values
152
+
153
+ # @return [String, nil]
154
+ attr_reader :placeholder
155
+
156
+ # @return [Array<Option>]
157
+ attr_reader :options
158
+
159
+ # @!visibility private
160
+ def initialize(data, bot)
161
+ @bot = bot
162
+
163
+ @max_values = data['max_values']
164
+ @min_values = data['min_values']
165
+ @placeholder = data['placeholder']
166
+ @custom_id = data['custom_id']
167
+ @emoji = Emoji.new(data['emoji'], @bot) if data['emoji']
168
+ @options = data['options'].map { |opt| Option.new(opt) }
169
+ end
170
+ end
171
+
172
+ # Text input component for use in modals. Can be either a line (`short`), or a multi line (`paragraph`) block.
173
+ class TextInput
174
+ # Single line text input
175
+ SHORT = 1
176
+ # Multi-line text input
177
+ PARAGRAPH = 2
178
+
179
+ # @return [String]
180
+ attr_reader :custom_id
181
+
182
+ # @return [Symbol]
183
+ attr_reader :style
184
+
185
+ # @return [String]
186
+ attr_reader :label
187
+
188
+ # @return [Integer, nil]
189
+ attr_reader :min_length
190
+
191
+ # @return [Integer, nil]
192
+ attr_reader :max_length
193
+
194
+ # @return [true, false]
195
+ attr_reader :required
196
+
197
+ # @return [String, nil]
198
+ attr_reader :value
199
+
200
+ # @return [String, nil]
201
+ attr_reader :placeholder
202
+
203
+ # @!visibility private
204
+ def initialize(data, bot)
205
+ @bot = bot
206
+ @style = data['style'] == SHORT ? :short : :paragraph
207
+ @label = data['label']
208
+ @min_length = data['min_length']
209
+ @max_length = data['max_length']
210
+ @required = data['required']
211
+ @value = data['value']
212
+ @placeholder = data['placeholder']
213
+ @custom_id = data['custom_id']
214
+ end
215
+
216
+ def short?
217
+ @style == :short
218
+ end
219
+
220
+ def paragraph?
221
+ @style == :paragraph
222
+ end
223
+
224
+ def required?
225
+ @required
226
+ end
227
+ end
228
+ end
229
+ end
@@ -5,9 +5,6 @@ module Discordrb
5
5
  # A freshly generated embed object will not appear in a message object
6
6
  # unless grabbed from its ID in a channel.
7
7
  class Embed
8
- # @return [Message] the message this embed object is contained in.
9
- attr_reader :message
10
-
11
8
  # @return [String] the URL this embed object is based on.
12
9
  attr_reader :url
13
10
 
@@ -70,6 +67,16 @@ module Discordrb
70
67
  @author = data['author'].nil? ? nil : EmbedAuthor.new(data['author'], self)
71
68
  @fields = data['fields'].nil? ? nil : data['fields'].map { |field| EmbedField.new(field, self) }
72
69
  end
70
+
71
+ # @return [Message, nil] the message this embed object is contained in.
72
+ def message
73
+ @message unless @message.is_a?(Snapshot)
74
+ end
75
+
76
+ # @return [Snapshot, nil] the message snapshot this embed object is contained in.
77
+ def snapshot
78
+ @message unless @message.is_a?(Message)
79
+ end
73
80
  end
74
81
 
75
82
  # An Embed footer for the embed object.
@@ -14,6 +14,21 @@ module Discordrb
14
14
  # @return [Array<Role>, nil] roles this emoji is active for, or nil if the emoji's server is unknown
15
15
  attr_reader :roles
16
16
 
17
+ # @return [User, nil] the user who uploaded this emoji, or nil if the emoji's server is unknown
18
+ attr_reader :creator
19
+
20
+ # @return [Boolean, nil] if the emoji requires colons to be used, or nil if the emoji's server is unknown
21
+ attr_reader :requires_colons
22
+ alias_method :requires_colons?, :requires_colons
23
+
24
+ # @return [Boolean, nil] whether this emoji is managed by an integration, or nil if the emoji's server is unknown
25
+ attr_reader :managed
26
+ alias_method :managed?, :managed
27
+
28
+ # @return [Boolean, nil] if this emoji is currently usable, or nil if the emoji's server is unknown
29
+ attr_reader :available
30
+ alias_method :available?, :available
31
+
17
32
  # @return [true, false] if the emoji is animated
18
33
  attr_reader :animated
19
34
  alias_method :animated?, :animated
@@ -25,8 +40,12 @@ module Discordrb
25
40
 
26
41
  @name = data['name']
27
42
  @server = server
28
- @id = data['id'].nil? ? nil : data['id'].to_i
43
+ @id = data['id']&.to_i
29
44
  @animated = data['animated']
45
+ @managed = data['managed']
46
+ @available = data['available']
47
+ @requires_colons = data['require_colons']
48
+ @creator = data['user'] ? bot.ensure_user(data['user']) : nil
30
49
 
31
50
  process_roles(data['roles']) if server
32
51
  end
@@ -9,12 +9,44 @@ module Discordrb
9
9
  # @return [Integer] this account's ID.
10
10
  attr_reader :id
11
11
 
12
+ # @!visibility private
12
13
  def initialize(data)
13
14
  @name = data['name']
14
15
  @id = data['id'].to_i
15
16
  end
16
17
  end
17
18
 
19
+ # Bot/OAuth2 application for discord integrations
20
+ class IntegrationApplication
21
+ # @return [Integer] the ID of the application.
22
+ attr_reader :id
23
+
24
+ # @return [String] the name of the application.
25
+ attr_reader :name
26
+
27
+ # @return [String, nil] the icon hash of the application.
28
+ attr_reader :icon
29
+
30
+ # @return [String] the description of the application.
31
+ attr_reader :description
32
+
33
+ # @return [String] the summary of the application.
34
+ attr_reader :summary
35
+
36
+ # @return [User, nil] the bot associated with this application.
37
+ attr_reader :bot
38
+
39
+ # @!visibility private
40
+ def initialize(data, bot)
41
+ @id = data['id'].to_i
42
+ @name = data['name']
43
+ @icon = data['icon']
44
+ @description = data['description']
45
+ @summary = data['summary']
46
+ @bot = Discordrb::User.new(data['user'], bot) if data['user']
47
+ end
48
+ end
49
+
18
50
  # Server integration
19
51
  class Integration
20
52
  include IDObject
@@ -28,8 +60,8 @@ module Discordrb
28
60
  # @return [User] the user the integration is linked to
29
61
  attr_reader :user
30
62
 
31
- # @return [Role, nil] the role that this integration uses for "subscribers"
32
- attr_reader :role
63
+ # @return [Integer, nil] the role that this integration uses for "subscribers"
64
+ attr_reader :role_id
33
65
 
34
66
  # @return [true, false] whether emoticons are enabled
35
67
  attr_reader :emoticon
@@ -57,6 +89,13 @@ module Discordrb
57
89
  # @return [Integer] the grace period before subscribers expire (in days)
58
90
  attr_reader :expire_grace_period
59
91
 
92
+ # @return [Integer, nil] how many subscribers this integration has.
93
+ attr_reader :subscriber_count
94
+
95
+ # @return [true, false] has this integration been revoked.
96
+ attr_reader :revoked
97
+
98
+ # @!visibility private
60
99
  def initialize(data, bot, server)
61
100
  @bot = bot
62
101
 
@@ -71,8 +110,11 @@ module Discordrb
71
110
  @expire_behaviour = %i[remove kick][data['expire_behavior']]
72
111
  @expire_grace_period = data['expire_grace_period']
73
112
  @user = @bot.ensure_user(data['user'])
74
- @role = server.role(data['role_id']) || nil
113
+ @role_id = data['role_id']&.to_i
75
114
  @emoticon = data['enable_emoticons']
115
+ @subscriber_count = data['subscriber_count']&.to_i
116
+ @revoked = data['revoked']
117
+ @application = IntegrationApplication.new(data['application'], bot) if data['application']
76
118
  end
77
119
 
78
120
  # The inspect method is overwritten to give more useful output