discordrb 3.3.0 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of discordrb might be problematic. Click here for more details.

Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +126 -0
  3. data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +0 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +25 -0
  6. data/.github/pull_request_template.md +37 -0
  7. data/.rubocop.yml +34 -37
  8. data/.travis.yml +5 -6
  9. data/CHANGELOG.md +472 -347
  10. data/Gemfile +2 -0
  11. data/LICENSE.txt +1 -1
  12. data/README.md +61 -79
  13. data/Rakefile +2 -0
  14. data/bin/console +1 -0
  15. data/discordrb-webhooks.gemspec +6 -6
  16. data/discordrb.gemspec +17 -17
  17. data/lib/discordrb.rb +73 -0
  18. data/lib/discordrb/allowed_mentions.rb +36 -0
  19. data/lib/discordrb/api.rb +40 -15
  20. data/lib/discordrb/api/channel.rb +57 -39
  21. data/lib/discordrb/api/invite.rb +3 -3
  22. data/lib/discordrb/api/server.rb +55 -50
  23. data/lib/discordrb/api/user.rb +8 -8
  24. data/lib/discordrb/api/webhook.rb +6 -6
  25. data/lib/discordrb/await.rb +0 -1
  26. data/lib/discordrb/bot.rb +164 -72
  27. data/lib/discordrb/cache.rb +4 -2
  28. data/lib/discordrb/colour_rgb.rb +43 -0
  29. data/lib/discordrb/commands/command_bot.rb +22 -6
  30. data/lib/discordrb/commands/container.rb +20 -23
  31. data/lib/discordrb/commands/parser.rb +18 -18
  32. data/lib/discordrb/commands/rate_limiter.rb +3 -2
  33. data/lib/discordrb/container.rb +77 -17
  34. data/lib/discordrb/data.rb +25 -4180
  35. data/lib/discordrb/data/activity.rb +264 -0
  36. data/lib/discordrb/data/application.rb +50 -0
  37. data/lib/discordrb/data/attachment.rb +56 -0
  38. data/lib/discordrb/data/audit_logs.rb +345 -0
  39. data/lib/discordrb/data/channel.rb +849 -0
  40. data/lib/discordrb/data/embed.rb +251 -0
  41. data/lib/discordrb/data/emoji.rb +82 -0
  42. data/lib/discordrb/data/integration.rb +83 -0
  43. data/lib/discordrb/data/invite.rb +137 -0
  44. data/lib/discordrb/data/member.rb +297 -0
  45. data/lib/discordrb/data/message.rb +334 -0
  46. data/lib/discordrb/data/overwrite.rb +102 -0
  47. data/lib/discordrb/data/profile.rb +91 -0
  48. data/lib/discordrb/data/reaction.rb +33 -0
  49. data/lib/discordrb/data/recipient.rb +34 -0
  50. data/lib/discordrb/data/role.rb +191 -0
  51. data/lib/discordrb/data/server.rb +1002 -0
  52. data/lib/discordrb/data/user.rb +204 -0
  53. data/lib/discordrb/data/voice_region.rb +45 -0
  54. data/lib/discordrb/data/voice_state.rb +41 -0
  55. data/lib/discordrb/data/webhook.rb +145 -0
  56. data/lib/discordrb/errors.rb +2 -1
  57. data/lib/discordrb/events/bans.rb +7 -5
  58. data/lib/discordrb/events/channels.rb +2 -0
  59. data/lib/discordrb/events/guilds.rb +16 -9
  60. data/lib/discordrb/events/invites.rb +125 -0
  61. data/lib/discordrb/events/members.rb +6 -2
  62. data/lib/discordrb/events/message.rb +69 -27
  63. data/lib/discordrb/events/presence.rb +14 -4
  64. data/lib/discordrb/events/raw.rb +1 -3
  65. data/lib/discordrb/events/reactions.rb +49 -3
  66. data/lib/discordrb/events/typing.rb +6 -4
  67. data/lib/discordrb/events/voice_server_update.rb +47 -0
  68. data/lib/discordrb/events/voice_state_update.rb +15 -10
  69. data/lib/discordrb/events/webhooks.rb +9 -6
  70. data/lib/discordrb/gateway.rb +72 -57
  71. data/lib/discordrb/id_object.rb +39 -0
  72. data/lib/discordrb/light/integrations.rb +1 -1
  73. data/lib/discordrb/light/light_bot.rb +1 -1
  74. data/lib/discordrb/logger.rb +4 -4
  75. data/lib/discordrb/paginator.rb +57 -0
  76. data/lib/discordrb/permissions.rb +103 -8
  77. data/lib/discordrb/version.rb +1 -1
  78. data/lib/discordrb/voice/encoder.rb +3 -3
  79. data/lib/discordrb/voice/network.rb +84 -43
  80. data/lib/discordrb/voice/sodium.rb +96 -0
  81. data/lib/discordrb/voice/voice_bot.rb +34 -26
  82. metadata +93 -55
@@ -0,0 +1,251 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discordrb
4
+ # An Embed object that is contained in a message
5
+ # A freshly generated embed object will not appear in a message object
6
+ # unless grabbed from its ID in a channel.
7
+ class Embed
8
+ # @return [Message] the message this embed object is contained in.
9
+ attr_reader :message
10
+
11
+ # @return [String] the URL this embed object is based on.
12
+ attr_reader :url
13
+
14
+ # @return [String, nil] the title of the embed object. `nil` if there is not a title
15
+ attr_reader :title
16
+
17
+ # @return [String, nil] the description of the embed object. `nil` if there is not a description
18
+ attr_reader :description
19
+
20
+ # @return [Symbol] the type of the embed object. Possible types are:
21
+ #
22
+ # * `:link`
23
+ # * `:video`
24
+ # * `:image`
25
+ attr_reader :type
26
+
27
+ # @return [Time, nil] the timestamp of the embed object. `nil` if there is not a timestamp
28
+ attr_reader :timestamp
29
+
30
+ # @return [String, nil] the color of the embed object. `nil` if there is not a color
31
+ attr_reader :color
32
+ alias_method :colour, :color
33
+
34
+ # @return [EmbedFooter, nil] the footer of the embed object. `nil` if there is not a footer
35
+ attr_reader :footer
36
+
37
+ # @return [EmbedProvider, nil] the provider of the embed object. `nil` if there is not a provider
38
+ attr_reader :provider
39
+
40
+ # @return [EmbedImage, nil] the image of the embed object. `nil` if there is not an image
41
+ attr_reader :image
42
+
43
+ # @return [EmbedThumbnail, nil] the thumbnail of the embed object. `nil` if there is not a thumbnail
44
+ attr_reader :thumbnail
45
+
46
+ # @return [EmbedVideo, nil] the video of the embed object. `nil` if there is not a video
47
+ attr_reader :video
48
+
49
+ # @return [EmbedAuthor, nil] the author of the embed object. `nil` if there is not an author
50
+ attr_reader :author
51
+
52
+ # @return [Array<EmbedField>, nil] the fields of the embed object. `nil` if there are no fields
53
+ attr_reader :fields
54
+
55
+ # @!visibility private
56
+ def initialize(data, message)
57
+ @message = message
58
+
59
+ @url = data['url']
60
+ @title = data['title']
61
+ @type = data['type'].to_sym
62
+ @description = data['description']
63
+ @timestamp = data['timestamp'].nil? ? nil : Time.parse(data['timestamp'])
64
+ @color = data['color']
65
+ @footer = data['footer'].nil? ? nil : EmbedFooter.new(data['footer'], self)
66
+ @image = data['image'].nil? ? nil : EmbedImage.new(data['image'], self)
67
+ @video = data['video'].nil? ? nil : EmbedVideo.new(data['video'], self)
68
+ @provider = data['provider'].nil? ? nil : EmbedProvider.new(data['provider'], self)
69
+ @thumbnail = data['thumbnail'].nil? ? nil : EmbedThumbnail.new(data['thumbnail'], self)
70
+ @author = data['author'].nil? ? nil : EmbedAuthor.new(data['author'], self)
71
+ @fields = data['fields'].nil? ? nil : data['fields'].map { |field| EmbedField.new(field, self) }
72
+ end
73
+ end
74
+
75
+ # An Embed footer for the embed object.
76
+ class EmbedFooter
77
+ # @return [Embed] the embed object this is based on.
78
+ attr_reader :embed
79
+
80
+ # @return [String] the footer text.
81
+ attr_reader :text
82
+
83
+ # @return [String] the URL of the footer icon.
84
+ attr_reader :icon_url
85
+
86
+ # @return [String] the proxied URL of the footer icon.
87
+ attr_reader :proxy_icon_url
88
+
89
+ # @!visibility private
90
+ def initialize(data, embed)
91
+ @embed = embed
92
+
93
+ @text = data['text']
94
+ @icon_url = data['icon_url']
95
+ @proxy_icon_url = data['proxy_icon_url']
96
+ end
97
+ end
98
+
99
+ # An Embed image for the embed object.
100
+ class EmbedImage
101
+ # @return [Embed] the embed object this is based on.
102
+ attr_reader :embed
103
+
104
+ # @return [String] the source URL of the image.
105
+ attr_reader :url
106
+
107
+ # @return [String] the proxy URL of the image.
108
+ attr_reader :proxy_url
109
+
110
+ # @return [Integer] the width of the image, in pixels.
111
+ attr_reader :width
112
+
113
+ # @return [Integer] the height of the image, in pixels.
114
+ attr_reader :height
115
+
116
+ # @!visibility private
117
+ def initialize(data, embed)
118
+ @embed = embed
119
+
120
+ @url = data['url']
121
+ @proxy_url = data['proxy_url']
122
+ @width = data['width']
123
+ @height = data['height']
124
+ end
125
+ end
126
+
127
+ # An Embed video for the embed object
128
+ class EmbedVideo
129
+ # @return [Embed] the embed object this is based on.
130
+ attr_reader :embed
131
+
132
+ # @return [String] the source URL of the video.
133
+ attr_reader :url
134
+
135
+ # @return [Integer] the width of the video, in pixels.
136
+ attr_reader :width
137
+
138
+ # @return [Integer] the height of the video, in pixels.
139
+ attr_reader :height
140
+
141
+ # @!visibility private
142
+ def initialize(data, embed)
143
+ @embed = embed
144
+
145
+ @url = data['url']
146
+ @width = data['width']
147
+ @height = data['height']
148
+ end
149
+ end
150
+
151
+ # An Embed thumbnail for the embed object
152
+ class EmbedThumbnail
153
+ # @return [Embed] the embed object this is based on.
154
+ attr_reader :embed
155
+
156
+ # @return [String] the CDN URL this thumbnail can be downloaded at.
157
+ attr_reader :url
158
+
159
+ # @return [String] the thumbnail's proxy URL - I'm not sure what exactly this does, but I think it has something to
160
+ # do with CDNs.
161
+ attr_reader :proxy_url
162
+
163
+ # @return [Integer] the width of this thumbnail file, in pixels.
164
+ attr_reader :width
165
+
166
+ # @return [Integer] the height of this thumbnail file, in pixels.
167
+ attr_reader :height
168
+
169
+ # @!visibility private
170
+ def initialize(data, embed)
171
+ @embed = embed
172
+
173
+ @url = data['url']
174
+ @proxy_url = data['proxy_url']
175
+ @width = data['width']
176
+ @height = data['height']
177
+ end
178
+ end
179
+
180
+ # An Embed provider for the embed object
181
+ class EmbedProvider
182
+ # @return [Embed] the embed object this is based on.
183
+ attr_reader :embed
184
+
185
+ # @return [String] the provider's name.
186
+ attr_reader :name
187
+
188
+ # @return [String, nil] the URL of the provider, or `nil` if there is no URL.
189
+ attr_reader :url
190
+
191
+ # @!visibility private
192
+ def initialize(data, embed)
193
+ @embed = embed
194
+
195
+ @name = data['name']
196
+ @url = data['url']
197
+ end
198
+ end
199
+
200
+ # An Embed author for the embed object
201
+ class EmbedAuthor
202
+ # @return [Embed] the embed object this is based on.
203
+ attr_reader :embed
204
+
205
+ # @return [String] the author's name.
206
+ attr_reader :name
207
+
208
+ # @return [String, nil] the URL of the author's website, or `nil` if there is no URL.
209
+ attr_reader :url
210
+
211
+ # @return [String, nil] the icon of the author, or `nil` if there is no icon.
212
+ attr_reader :icon_url
213
+
214
+ # @return [String, nil] the Discord proxy URL, or `nil` if there is no `icon_url`.
215
+ attr_reader :proxy_icon_url
216
+
217
+ # @!visibility private
218
+ def initialize(data, embed)
219
+ @embed = embed
220
+
221
+ @name = data['name']
222
+ @url = data['url']
223
+ @icon_url = data['icon_url']
224
+ @proxy_icon_url = data['proxy_icon_url']
225
+ end
226
+ end
227
+
228
+ # An Embed field for the embed object
229
+ class EmbedField
230
+ # @return [Embed] the embed object this is based on.
231
+ attr_reader :embed
232
+
233
+ # @return [String] the field's name.
234
+ attr_reader :name
235
+
236
+ # @return [String] the field's value.
237
+ attr_reader :value
238
+
239
+ # @return [true, false] whether this field is inline.
240
+ attr_reader :inline
241
+
242
+ # @!visibility private
243
+ def initialize(data, embed)
244
+ @embed = embed
245
+
246
+ @name = data['name']
247
+ @value = data['value']
248
+ @inline = data['inline']
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discordrb
4
+ # Server emoji
5
+ class Emoji
6
+ include IDObject
7
+
8
+ # @return [String] the emoji name
9
+ attr_reader :name
10
+
11
+ # @return [Server, nil] the server of this emoji
12
+ attr_reader :server
13
+
14
+ # @return [Array<Role>, nil] roles this emoji is active for, or nil if the emoji's server is unknown
15
+ attr_reader :roles
16
+
17
+ # @return [true, false] if the emoji is animated
18
+ attr_reader :animated
19
+ alias_method :animated?, :animated
20
+
21
+ # @!visibility private
22
+ def initialize(data, bot, server = nil)
23
+ @bot = bot
24
+ @roles = nil
25
+
26
+ @name = data['name']
27
+ @server = server
28
+ @id = data['id'].nil? ? nil : data['id'].to_i
29
+ @animated = data['animated']
30
+
31
+ process_roles(data['roles']) if server
32
+ end
33
+
34
+ # ID or name based comparison
35
+ def ==(other)
36
+ return false unless other.is_a? Emoji
37
+ return Discordrb.id_compare(@id, other) if @id
38
+
39
+ name == other.name
40
+ end
41
+
42
+ alias_method :eql?, :==
43
+
44
+ # @return [String] the layout to mention it (or have it used) in a message
45
+ def mention
46
+ return name if id.nil?
47
+
48
+ "<#{'a' if animated}:#{name}:#{id}>"
49
+ end
50
+
51
+ alias_method :use, :mention
52
+ alias_method :to_s, :mention
53
+
54
+ # @return [String] the layout to use this emoji in a reaction
55
+ def to_reaction
56
+ return name if id.nil?
57
+
58
+ "#{name}:#{id}"
59
+ end
60
+
61
+ # @return [String] the icon URL of the emoji
62
+ def icon_url
63
+ API.emoji_icon_url(id)
64
+ end
65
+
66
+ # The inspect method is overwritten to give more useful output
67
+ def inspect
68
+ "<Emoji name=#{name} id=#{id} animated=#{animated}>"
69
+ end
70
+
71
+ # @!visibility private
72
+ def process_roles(roles)
73
+ @roles = []
74
+ return unless roles
75
+
76
+ roles.each do |role_id|
77
+ role = server.role(role_id)
78
+ @roles << role
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discordrb
4
+ # Integration Account
5
+ class IntegrationAccount
6
+ # @return [String] this account's name.
7
+ attr_reader :name
8
+
9
+ # @return [Integer] this account's ID.
10
+ attr_reader :id
11
+
12
+ def initialize(data)
13
+ @name = data['name']
14
+ @id = data['id'].to_i
15
+ end
16
+ end
17
+
18
+ # Server integration
19
+ class Integration
20
+ include IDObject
21
+
22
+ # @return [String] the integration name
23
+ attr_reader :name
24
+
25
+ # @return [Server] the server the integration is linked to
26
+ attr_reader :server
27
+
28
+ # @return [User] the user the integration is linked to
29
+ attr_reader :user
30
+
31
+ # @return [Role, nil] the role that this integration uses for "subscribers"
32
+ attr_reader :role
33
+
34
+ # @return [true, false] whether emoticons are enabled
35
+ attr_reader :emoticon
36
+ alias_method :emoticon?, :emoticon
37
+
38
+ # @return [String] the integration type (YouTube, Twitch, etc.)
39
+ attr_reader :type
40
+
41
+ # @return [true, false] whether the integration is enabled
42
+ attr_reader :enabled
43
+
44
+ # @return [true, false] whether the integration is syncing
45
+ attr_reader :syncing
46
+
47
+ # @return [IntegrationAccount] the integration account information
48
+ attr_reader :account
49
+
50
+ # @return [Time] the time the integration was synced at
51
+ attr_reader :synced_at
52
+
53
+ # @return [Symbol] the behaviour of expiring subscribers (:remove = Remove User from role; :kick = Kick User from server)
54
+ attr_reader :expire_behaviour
55
+ alias_method :expire_behavior, :expire_behaviour
56
+
57
+ # @return [Integer] the grace period before subscribers expire (in days)
58
+ attr_reader :expire_grace_period
59
+
60
+ def initialize(data, bot, server)
61
+ @bot = bot
62
+
63
+ @name = data['name']
64
+ @server = server
65
+ @id = data['id'].to_i
66
+ @enabled = data['enabled']
67
+ @syncing = data['syncing']
68
+ @type = data['type']
69
+ @account = IntegrationAccount.new(data['account'])
70
+ @synced_at = Time.parse(data['synced_at'])
71
+ @expire_behaviour = %i[remove kick][data['expire_behavior']]
72
+ @expire_grace_period = data['expire_grace_period']
73
+ @user = @bot.ensure_user(data['user'])
74
+ @role = server.role(data['role_id']) || nil
75
+ @emoticon = data['enable_emoticons']
76
+ end
77
+
78
+ # The inspect method is overwritten to give more useful output
79
+ def inspect
80
+ "<Integration name=#{@name} id=#{@id} type=#{@type} enabled=#{@enabled}>"
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discordrb
4
+ # A channel referenced by an invite. It has less data than regular channels, so it's a separate class
5
+ class InviteChannel
6
+ include IDObject
7
+
8
+ # @return [String] this channel's name.
9
+ attr_reader :name
10
+
11
+ # @return [Integer] this channel's type (0: text, 1: private, 2: voice, 3: group).
12
+ attr_reader :type
13
+
14
+ # @!visibility private
15
+ def initialize(data, bot)
16
+ @bot = bot
17
+
18
+ @id = data['id'].to_i
19
+ @name = data['name']
20
+ @type = data['type']
21
+ end
22
+ end
23
+
24
+ # A server referenced to by an invite
25
+ class InviteServer
26
+ include IDObject
27
+
28
+ # @return [String] this server's name.
29
+ attr_reader :name
30
+
31
+ # @return [String, nil] the hash of the server's invite splash screen (for partnered servers) or nil if none is
32
+ # present
33
+ attr_reader :splash_hash
34
+
35
+ # @!visibility private
36
+ def initialize(data, bot)
37
+ @bot = bot
38
+
39
+ @id = data['id'].to_i
40
+ @name = data['name']
41
+ @splash_hash = data['splash_hash']
42
+ end
43
+ end
44
+
45
+ # A Discord invite to a channel
46
+ class Invite
47
+ # @return [InviteChannel, Channel] the channel this invite references.
48
+ attr_reader :channel
49
+
50
+ # @return [InviteServer, Server] the server this invite references.
51
+ attr_reader :server
52
+
53
+ # @return [Integer] the amount of uses left on this invite.
54
+ attr_reader :uses
55
+ alias_method :max_uses, :uses
56
+
57
+ # @return [User, nil] the user that made this invite. May also be nil if the user can't be determined.
58
+ attr_reader :inviter
59
+ alias_method :user, :inviter
60
+
61
+ # @return [true, false] whether or not this invite grants temporary membership. If someone joins a server with this invite, they will be removed from the server when they go offline unless they've received a role.
62
+ attr_reader :temporary
63
+ alias_method :temporary?, :temporary
64
+
65
+ # @return [true, false] whether this invite is still valid.
66
+ attr_reader :revoked
67
+ alias_method :revoked?, :revoked
68
+
69
+ # @return [String] this invite's code
70
+ attr_reader :code
71
+
72
+ # @return [Integer, nil] the amount of members in the server. Will be nil if it has not been resolved.
73
+ attr_reader :member_count
74
+ alias_method :user_count, :member_count
75
+
76
+ # @return [Integer, nil] the amount of online members in the server. Will be nil if it has not been resolved.
77
+ attr_reader :online_member_count
78
+ alias_method :online_user_count, :online_member_count
79
+
80
+ # @return [Integer, nil] the invites max age before it expires, or nil if it's unknown. If the max age is 0, the invite will never expire unless it's deleted.
81
+ attr_reader :max_age
82
+
83
+ # @return [Time, nil] when this invite was created, or nil if it's unknown
84
+ attr_reader :created_at
85
+
86
+ # @!visibility private
87
+ def initialize(data, bot)
88
+ @bot = bot
89
+
90
+ @channel = if data['channel_id'] || bot.channel
91
+ bot.channel(data['channel_id'])
92
+ else
93
+ InviteChannel.new(data['channel'], bot)
94
+ end
95
+
96
+ @server = if data['guild_id']
97
+ bot.server(data['guild_id'])
98
+ else
99
+ InviteServer.new(data['guild'], bot)
100
+ end
101
+
102
+ @uses = data['uses']
103
+ @inviter = data['inviter'] ? (@bot.user(data['inviter']['id'].to_i) || User.new(data['inviter'], bot)) : nil
104
+ @temporary = data['temporary']
105
+ @revoked = data['revoked']
106
+ @online_member_count = data['approximate_presence_count']
107
+ @member_count = data['approximate_member_count']
108
+ @max_age = data['max_age']
109
+ @created_at = data['created_at']
110
+
111
+ @code = data['code']
112
+ end
113
+
114
+ # Code based comparison
115
+ def ==(other)
116
+ other.respond_to?(:code) ? (@code == other.code) : (@code == other)
117
+ end
118
+
119
+ # Deletes this invite
120
+ # @param reason [String] The reason the invite is being deleted.
121
+ def delete(reason = nil)
122
+ API::Invite.delete(@bot.token, @code, reason)
123
+ end
124
+
125
+ alias_method :revoke, :delete
126
+
127
+ # The inspect method is overwritten to give more useful output
128
+ def inspect
129
+ "<Invite code=#{@code} channel=#{@channel} uses=#{@uses} temporary=#{@temporary} revoked=#{@revoked} created_at=#{@created_at} max_age=#{@max_age}>"
130
+ end
131
+
132
+ # Creates an invite URL.
133
+ def url
134
+ "https://discord.gg/#{@code}"
135
+ end
136
+ end
137
+ end