onyxcord 1.1.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 (133) hide show
  1. checksums.yaml +7 -0
  2. data/.devcontainer/Dockerfile +13 -0
  3. data/.devcontainer/devcontainer.json +29 -0
  4. data/.devcontainer/postcreate.sh +4 -0
  5. data/.github/CONTRIBUTING.md +13 -0
  6. data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  7. data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
  8. data/.github/pull_request_template.md +37 -0
  9. data/.github/workflows/ci.yml +78 -0
  10. data/.github/workflows/codeql.yml +65 -0
  11. data/.github/workflows/deploy.yml +54 -0
  12. data/.github/workflows/release.yml +51 -0
  13. data/.gitignore +16 -0
  14. data/.markdownlint.json +4 -0
  15. data/.overcommit.yml +7 -0
  16. data/.rspec +2 -0
  17. data/.rubocop.yml +129 -0
  18. data/.yardopts +1 -0
  19. data/CHANGELOG.md +0 -0
  20. data/Gemfile +7 -0
  21. data/LICENSE.txt +21 -0
  22. data/README.md +305 -0
  23. data/Rakefile +17 -0
  24. data/bin/console +15 -0
  25. data/bin/setup +7 -0
  26. data/lib/onyxcord/allowed_mentions.rb +43 -0
  27. data/lib/onyxcord/api/application.rb +316 -0
  28. data/lib/onyxcord/api/channel.rb +700 -0
  29. data/lib/onyxcord/api/interaction.rb +67 -0
  30. data/lib/onyxcord/api/invite.rb +44 -0
  31. data/lib/onyxcord/api/server.rb +775 -0
  32. data/lib/onyxcord/api/user.rb +158 -0
  33. data/lib/onyxcord/api/webhook.rb +163 -0
  34. data/lib/onyxcord/api.rb +335 -0
  35. data/lib/onyxcord/await.rb +51 -0
  36. data/lib/onyxcord/bot.rb +1971 -0
  37. data/lib/onyxcord/cache.rb +326 -0
  38. data/lib/onyxcord/colour_rgb.rb +43 -0
  39. data/lib/onyxcord/commands/command_bot.rb +511 -0
  40. data/lib/onyxcord/commands/container.rb +112 -0
  41. data/lib/onyxcord/commands/events.rb +11 -0
  42. data/lib/onyxcord/commands/parser.rb +327 -0
  43. data/lib/onyxcord/commands/rate_limiter.rb +144 -0
  44. data/lib/onyxcord/configuration.rb +125 -0
  45. data/lib/onyxcord/container.rb +988 -0
  46. data/lib/onyxcord/data/activity.rb +271 -0
  47. data/lib/onyxcord/data/application.rb +341 -0
  48. data/lib/onyxcord/data/attachment.rb +91 -0
  49. data/lib/onyxcord/data/audit_logs.rb +438 -0
  50. data/lib/onyxcord/data/avatar_decoration.rb +26 -0
  51. data/lib/onyxcord/data/call.rb +22 -0
  52. data/lib/onyxcord/data/channel.rb +1355 -0
  53. data/lib/onyxcord/data/channel_tag.rb +69 -0
  54. data/lib/onyxcord/data/collectibles.rb +47 -0
  55. data/lib/onyxcord/data/component.rb +583 -0
  56. data/lib/onyxcord/data/embed.rb +258 -0
  57. data/lib/onyxcord/data/emoji.rb +123 -0
  58. data/lib/onyxcord/data/install_params.rb +24 -0
  59. data/lib/onyxcord/data/integration.rb +144 -0
  60. data/lib/onyxcord/data/interaction.rb +1141 -0
  61. data/lib/onyxcord/data/invite.rb +137 -0
  62. data/lib/onyxcord/data/member.rb +528 -0
  63. data/lib/onyxcord/data/message.rb +612 -0
  64. data/lib/onyxcord/data/message_activity.rb +41 -0
  65. data/lib/onyxcord/data/overwrite.rb +109 -0
  66. data/lib/onyxcord/data/poll.rb +365 -0
  67. data/lib/onyxcord/data/primary_server.rb +60 -0
  68. data/lib/onyxcord/data/profile.rb +79 -0
  69. data/lib/onyxcord/data/reaction.rb +64 -0
  70. data/lib/onyxcord/data/recipient.rb +34 -0
  71. data/lib/onyxcord/data/role.rb +449 -0
  72. data/lib/onyxcord/data/role_connection_data.rb +69 -0
  73. data/lib/onyxcord/data/role_subscription.rb +41 -0
  74. data/lib/onyxcord/data/scheduled_event.rb +513 -0
  75. data/lib/onyxcord/data/server.rb +1614 -0
  76. data/lib/onyxcord/data/server_preview.rb +68 -0
  77. data/lib/onyxcord/data/snapshot.rb +112 -0
  78. data/lib/onyxcord/data/team.rb +98 -0
  79. data/lib/onyxcord/data/timestamp.rb +69 -0
  80. data/lib/onyxcord/data/user.rb +324 -0
  81. data/lib/onyxcord/data/voice_region.rb +46 -0
  82. data/lib/onyxcord/data/voice_state.rb +41 -0
  83. data/lib/onyxcord/data/webhook.rb +238 -0
  84. data/lib/onyxcord/data.rb +57 -0
  85. data/lib/onyxcord/errors.rb +246 -0
  86. data/lib/onyxcord/event_executor.rb +80 -0
  87. data/lib/onyxcord/events/await.rb +48 -0
  88. data/lib/onyxcord/events/bans.rb +60 -0
  89. data/lib/onyxcord/events/channels.rb +225 -0
  90. data/lib/onyxcord/events/generic.rb +129 -0
  91. data/lib/onyxcord/events/guilds.rb +269 -0
  92. data/lib/onyxcord/events/integrations.rb +100 -0
  93. data/lib/onyxcord/events/interactions.rb +624 -0
  94. data/lib/onyxcord/events/invites.rb +127 -0
  95. data/lib/onyxcord/events/lifetime.rb +31 -0
  96. data/lib/onyxcord/events/members.rb +110 -0
  97. data/lib/onyxcord/events/message.rb +399 -0
  98. data/lib/onyxcord/events/polls.rb +118 -0
  99. data/lib/onyxcord/events/presence.rb +131 -0
  100. data/lib/onyxcord/events/raw.rb +74 -0
  101. data/lib/onyxcord/events/reactions.rb +218 -0
  102. data/lib/onyxcord/events/roles.rb +87 -0
  103. data/lib/onyxcord/events/scheduled_events.rb +171 -0
  104. data/lib/onyxcord/events/threads.rb +100 -0
  105. data/lib/onyxcord/events/typing.rb +73 -0
  106. data/lib/onyxcord/events/voice_server_update.rb +48 -0
  107. data/lib/onyxcord/events/voice_state_update.rb +106 -0
  108. data/lib/onyxcord/events/webhooks.rb +65 -0
  109. data/lib/onyxcord/gateway.rb +890 -0
  110. data/lib/onyxcord/id_object.rb +39 -0
  111. data/lib/onyxcord/light/data.rb +62 -0
  112. data/lib/onyxcord/light/integrations.rb +73 -0
  113. data/lib/onyxcord/light/light_bot.rb +58 -0
  114. data/lib/onyxcord/light.rb +8 -0
  115. data/lib/onyxcord/logger.rb +120 -0
  116. data/lib/onyxcord/message_components.rb +70 -0
  117. data/lib/onyxcord/paginator.rb +60 -0
  118. data/lib/onyxcord/permissions.rb +255 -0
  119. data/lib/onyxcord/rate_limiter/gateway.rb +42 -0
  120. data/lib/onyxcord/rate_limiter/rest.rb +89 -0
  121. data/lib/onyxcord/version.rb +7 -0
  122. data/lib/onyxcord/voice/encoder.rb +115 -0
  123. data/lib/onyxcord/voice/network.rb +380 -0
  124. data/lib/onyxcord/voice/opcodes.rb +29 -0
  125. data/lib/onyxcord/voice/sodium.rb +157 -0
  126. data/lib/onyxcord/voice/timer.rb +19 -0
  127. data/lib/onyxcord/voice/voice_bot.rb +386 -0
  128. data/lib/onyxcord/webhooks.rb +14 -0
  129. data/lib/onyxcord/websocket.rb +62 -0
  130. data/lib/onyxcord.rb +180 -0
  131. data/onyxcord-webhooks.gemspec +30 -0
  132. data/onyxcord.gemspec +50 -0
  133. metadata +421 -0
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ # Voice regions are the locations of servers that handle voice communication in Discord
5
+ class VoiceRegion
6
+ # @return [String] unique ID for the region
7
+ attr_reader :id
8
+ alias_method :to_s, :id
9
+
10
+ # @return [String] name of the region
11
+ attr_reader :name
12
+
13
+ # @return [String] an example hostname for the region
14
+ attr_reader :sample_hostname
15
+
16
+ # @return [Integer] an example port for the region
17
+ attr_reader :sample_port
18
+
19
+ # @return [true, false] if this is a VIP-only server
20
+ attr_reader :vip
21
+
22
+ # @return [true, false] if this voice server is the closest to the client
23
+ attr_reader :optimal
24
+
25
+ # @return [true, false] whether this is a deprecated voice region (avoid switching to these)
26
+ attr_reader :deprecated
27
+
28
+ # @return [true, false] whether this is a custom voice region (used for events/etc)
29
+ attr_reader :custom
30
+
31
+ # @!visibility private
32
+ def initialize(data)
33
+ @id = data['id']
34
+
35
+ @name = data['name']
36
+
37
+ @sample_hostname = data['sample_hostname']
38
+ @sample_port = data['sample_port']
39
+
40
+ @vip = data['vip']
41
+ @optimal = data['optimal']
42
+ @deprecated = data['deprecated']
43
+ @custom = data['custom']
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ # A voice state represents the state of a member's connection to a voice channel. It includes data like the voice
5
+ # channel the member is connected to and mute/deaf flags.
6
+ class VoiceState
7
+ # @return [Integer] the ID of the user whose voice state is represented by this object.
8
+ attr_reader :user_id
9
+
10
+ # @return [true, false] whether this voice state's member is muted server-wide.
11
+ attr_reader :mute
12
+
13
+ # @return [true, false] whether this voice state's member is deafened server-wide.
14
+ attr_reader :deaf
15
+
16
+ # @return [true, false] whether this voice state's member has muted themselves.
17
+ attr_reader :self_mute
18
+
19
+ # @return [true, false] whether this voice state's member has deafened themselves.
20
+ attr_reader :self_deaf
21
+
22
+ # @return [Channel] the voice channel this voice state's member is in.
23
+ attr_reader :voice_channel
24
+
25
+ # @!visibility private
26
+ def initialize(user_id)
27
+ @user_id = user_id
28
+ end
29
+
30
+ # Update this voice state with new data from Discord
31
+ # @note For internal use only.
32
+ # @!visibility private
33
+ def update(channel, mute, deaf, self_mute, self_deaf)
34
+ @voice_channel = channel
35
+ @mute = mute
36
+ @deaf = deaf
37
+ @self_mute = self_mute
38
+ @self_deaf = self_deaf
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onyxcord/webhooks/builder'
4
+ require 'onyxcord/webhooks/view'
5
+ require 'onyxcord/message_components'
6
+
7
+ module OnyxCord
8
+ # A webhook on a server channel
9
+ class Webhook
10
+ include IDObject
11
+
12
+ # @return [String] the webhook name.
13
+ attr_reader :name
14
+
15
+ # @return [Channel] the channel that the webhook is currently connected to.
16
+ attr_reader :channel
17
+
18
+ # @return [Server] the server that the webhook is currently connected to.
19
+ attr_reader :server
20
+
21
+ # @return [String, nil] the webhook's token, if this is an Incoming Webhook.
22
+ attr_reader :token
23
+
24
+ # @return [String] the webhook's avatar id.
25
+ attr_reader :avatar
26
+
27
+ # @return [Integer] the webhook's type (1: Incoming, 2: Channel Follower)
28
+ attr_reader :type
29
+
30
+ # Gets the user object of the creator of the webhook. May be limited to username, discriminator,
31
+ # ID and avatar if the bot cannot reach the owner
32
+ # @return [Member, User, nil] the user object of the owner or nil if the webhook was requested using the token.
33
+ attr_reader :owner
34
+
35
+ # @!visibility private
36
+ def initialize(data, bot)
37
+ @bot = bot
38
+
39
+ @name = data['name']
40
+ @id = data['id'].to_i
41
+ @channel = bot.channel(data['channel_id'])
42
+ @server = @channel.server
43
+ @token = data['token']
44
+ @avatar = data['avatar']
45
+ @type = data['type']
46
+
47
+ # Will not exist if the data was requested through a webhook token
48
+ return unless data['user']
49
+
50
+ @owner = @server.member(data['user']['id'].to_i)
51
+ return if @owner
52
+
53
+ OnyxCord::LOGGER.debug("Member with ID #{data['user']['id']} not cached (possibly left the server).")
54
+ @owner = @bot.ensure_user(data['user'])
55
+ end
56
+
57
+ # Sets the webhook's avatar.
58
+ # @param avatar [String, #read] The new avatar, in base64-encoded JPG format.
59
+ def avatar=(avatar)
60
+ update_webhook(avatar: avatarise(avatar))
61
+ end
62
+
63
+ # Deletes the webhook's avatar.
64
+ def delete_avatar
65
+ update_webhook(avatar: nil)
66
+ end
67
+
68
+ # Sets the webhook's channel
69
+ # @param channel [Channel, String, Integer] The channel the webhook should use.
70
+ def channel=(channel)
71
+ update_webhook(channel_id: channel.resolve_id)
72
+ end
73
+
74
+ # Sets the webhook's name.
75
+ # @param name [String] The webhook's new name.
76
+ def name=(name)
77
+ update_webhook(name: name)
78
+ end
79
+
80
+ # Updates the webhook if you need to edit more than 1 attribute.
81
+ # @param data [Hash] the data to update.
82
+ # @option data [String, #read, nil] :avatar The new avatar, in base64-encoded JPG format, or nil to delete the avatar.
83
+ # @option data [Channel, String, Integer] :channel The channel the webhook should use.
84
+ # @option data [String] :name The webhook's new name.
85
+ # @option data [String] :reason The reason for the webhook changes.
86
+ def update(data)
87
+ # Only pass a value for avatar if the key is defined as sending nil will delete the
88
+ data[:avatar] = avatarise(data[:avatar]) if data.key?(:avatar)
89
+ data[:channel_id] = data[:channel]&.resolve_id
90
+ data.delete(:channel)
91
+ update_webhook(**data)
92
+ end
93
+
94
+ # Deletes the webhook.
95
+ # @param reason [String] The reason the webhook is being deleted.
96
+ def delete(reason = nil)
97
+ if token?
98
+ API::Webhook.token_delete_webhook(@token, @id, reason)
99
+ else
100
+ API::Webhook.delete_webhook(@bot.token, @id, reason)
101
+ end
102
+ end
103
+
104
+ # Execute a webhook.
105
+ # @param content [String] The content of the message. May be 2000 characters long at most.
106
+ # @param username [String] The username the webhook will display as. If this is not set, the default username set in the webhook's settings.
107
+ # @param avatar_url [String] The URL of an image file to be used as an avatar. If this is not set, the default avatar from the webhook's
108
+ # @param tts [true, false] Whether this message should use TTS or not. By default, it doesn't.
109
+ # @param file [File] File to be sent together with the message. Mutually exclusive with embeds; a webhook message can contain
110
+ # either a file to be sent or embeds.
111
+ # @param embeds [Array<Webhooks::Embed, Hash>] Embeds to attach to this message.
112
+ # @param allowed_mentions [AllowedMentions, Hash] Mentions that are allowed to ping in the `content`.
113
+ # @param wait [true, false] Whether Discord should wait for the message to be successfully received by clients, or
114
+ # whether it should return immediately after sending the message. If `true` a {Message} object will be returned.
115
+ # @yield [builder] Gives the builder to the block to add additional steps, or to do the entire building process.
116
+ # @yieldparam builder [Builder] The builder given as a parameter which is used as the initial step to start from.
117
+ # @example Execute the webhook with kwargs
118
+ # client.execute(
119
+ # content: 'Testing',
120
+ # username: 'onyxcord',
121
+ # embeds: [
122
+ # { timestamp: Time.now.iso8601, title: 'testing', image: { url: 'https://i.imgur.com/PcMltU7.jpg' } }
123
+ # ])
124
+ # @example Execute the webhook with an already existing builder
125
+ # builder = OnyxCord::Webhooks::Builder.new # ...
126
+ # client.execute(builder)
127
+ # @example Execute the webhook by building a new message
128
+ # client.execute do |builder|
129
+ # builder.content = 'Testing'
130
+ # builder.username = 'onyxcord'
131
+ # builder.add_embed do |embed|
132
+ # embed.timestamp = Time.now
133
+ # embed.title = 'Testing'
134
+ # embed.image = OnyxCord::Webhooks::EmbedImage.new(url: 'https://i.imgur.com/PcMltU7.jpg')
135
+ # end
136
+ # end
137
+ # @return [Message, nil] If `wait` is `true`, a {Message} will be returned. Otherwise this method will return `nil`.
138
+ # @note This is only available to webhooks with publically exposed tokens. This excludes channel follow webhooks and webhooks retrieved
139
+ # via the audit log.
140
+ def execute(content: nil, username: nil, avatar_url: nil, tts: nil, file: nil, embeds: nil, allowed_mentions: nil, wait: true, builder: nil, components: nil, flags: 0, has_components: false, components_v2: false)
141
+ raise OnyxCord::Errors::UnauthorizedWebhook unless @token
142
+
143
+ params = { content: content, username: username, avatar_url: avatar_url, tts: tts, file: file, embeds: embeds, allowed_mentions: allowed_mentions }
144
+
145
+ builder ||= Webhooks::Builder.new
146
+ view = Webhooks::View.new
147
+
148
+ yield(builder, view) if block_given?
149
+
150
+ data = builder.to_json_hash.merge(params.compact)
151
+ components ||= view
152
+ flags = OnyxCord::MessageComponents.apply_v2_flag(flags, components, force: has_components || components_v2)
153
+
154
+ resp = API::Webhook.token_execute_webhook(@token, @id, wait, data[:content], data[:username], data[:avatar_url], data[:tts], data[:file], data[:embeds], data[:allowed_mentions], flags, components.to_a)
155
+
156
+ Message.new(JSON.parse(resp), @bot) if wait
157
+ end
158
+
159
+ # Delete a message created by this webhook.
160
+ # @param message [Message, String, Integer] The ID of the message to delete.
161
+ def delete_message(message)
162
+ raise OnyxCord::Errors::UnauthorizedWebhook unless @token
163
+
164
+ API::Webhook.token_delete_message(@token, @id, message.resolve_id)
165
+ end
166
+
167
+ # Edit a message created by this webhook.
168
+ # @param message [Message, String, Integer] The ID of the message to edit.
169
+ # @param content [String] The content of the message. May be 2000 characters long at most.
170
+ # @param embeds [Array<Webhooks::Embed, Hash>] Embeds to be attached to the message.
171
+ # @param allowed_mentions [AllowedMentions, Hash] Mentions that are allowed to ping in the `content`.
172
+ # @param builder [Builder, nil] The builder to start out with, or nil if one should be created anew.
173
+ # @yield [builder] Gives the builder to the block to add additional steps, or to do the entire building process.
174
+ # @yieldparam builder [Webhooks::Builder] The builder given as a parameter which is used as the initial step to start from.
175
+ # @return [Message] The updated message.
176
+ # @param components [View, Array<Hash>] Interaction components to associate with this message.
177
+ # @note When editing `allowed_mentions`, it will update visually in the client but not alert the user with a notification.
178
+ def edit_message(message, content: nil, embeds: nil, allowed_mentions: nil, builder: nil, components: nil, flags: 0, has_components: false, components_v2: false)
179
+ raise OnyxCord::Errors::UnauthorizedWebhook unless @token
180
+
181
+ params = { content: content, embeds: embeds, allowed_mentions: allowed_mentions }.compact
182
+
183
+ builder ||= Webhooks::Builder.new
184
+ view ||= Webhooks::View.new
185
+
186
+ yield(builder, view) if block_given?
187
+
188
+ data = builder.to_json_hash.merge(params.compact)
189
+ components ||= view
190
+ flags = OnyxCord::MessageComponents.apply_v2_flag(flags, components, force: has_components || components_v2)
191
+
192
+ resp = API::Webhook.token_edit_message(@token, @id, message.resolve_id, data[:content], data[:embeds], data[:allowed_mentions], components.to_a, nil, flags)
193
+ Message.new(JSON.parse(resp), @bot)
194
+ end
195
+
196
+ # Utility function to get a webhook's avatar URL.
197
+ # @return [String] the URL to the avatar image
198
+ def avatar_url
199
+ return API::User.default_avatar(@id) unless @avatar
200
+
201
+ API::User.avatar_url(@id, @avatar)
202
+ end
203
+
204
+ # The `inspect` method is overwritten to give more useful output.
205
+ def inspect
206
+ "<Webhook name=#{@name} id=#{@id}>"
207
+ end
208
+
209
+ # Utility function to know if the webhook was requested through a webhook token, rather than auth.
210
+ # @return [true, false] whether the webhook was requested by token or not.
211
+ def token?
212
+ @owner.nil?
213
+ end
214
+
215
+ private
216
+
217
+ def avatarise(avatar)
218
+ avatar.respond_to?(:read) ? OnyxCord.encode64(avatar) : avatar
219
+ end
220
+
221
+ def update_internal(data)
222
+ @name = data['name']
223
+ @avatar_id = data['avatar']
224
+ @channel = @bot.channel(data['channel_id'])
225
+ end
226
+
227
+ def update_webhook(new_data)
228
+ reason = new_data.delete(:reason)
229
+ data = JSON.parse(if token?
230
+ API::Webhook.token_update_webhook(@token, @id, new_data, reason)
231
+ else
232
+ API::Webhook.update_webhook(@bot.token, @id, new_data, reason)
233
+ end)
234
+ # Only update cache if API call worked
235
+ update_internal(data) if data['name']
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onyxcord/allowed_mentions'
4
+ require 'onyxcord/permissions'
5
+ require 'onyxcord/id_object'
6
+ require 'onyxcord/colour_rgb'
7
+ require 'onyxcord/errors'
8
+ require 'onyxcord/api'
9
+ require 'onyxcord/api/channel'
10
+ require 'onyxcord/api/server'
11
+ require 'onyxcord/api/invite'
12
+ require 'onyxcord/api/user'
13
+ require 'onyxcord/api/webhook'
14
+ require 'onyxcord/webhooks/embeds'
15
+ require 'onyxcord/webhooks/view'
16
+ require 'onyxcord/paginator'
17
+ require 'time'
18
+ require 'base64'
19
+
20
+ require 'onyxcord/data/activity'
21
+ require 'onyxcord/data/application'
22
+ require 'onyxcord/data/user'
23
+ require 'onyxcord/data/voice_state'
24
+ require 'onyxcord/data/voice_region'
25
+ require 'onyxcord/data/member'
26
+ require 'onyxcord/data/recipient'
27
+ require 'onyxcord/data/profile'
28
+ require 'onyxcord/data/role'
29
+ require 'onyxcord/data/invite'
30
+ require 'onyxcord/data/overwrite'
31
+ require 'onyxcord/data/channel'
32
+ require 'onyxcord/data/embed'
33
+ require 'onyxcord/data/attachment'
34
+ require 'onyxcord/data/message'
35
+ require 'onyxcord/data/reaction'
36
+ require 'onyxcord/data/emoji'
37
+ require 'onyxcord/data/integration'
38
+ require 'onyxcord/data/server'
39
+ require 'onyxcord/data/webhook'
40
+ require 'onyxcord/data/audit_logs'
41
+ require 'onyxcord/data/interaction'
42
+ require 'onyxcord/data/component'
43
+ require 'onyxcord/data/avatar_decoration'
44
+ require 'onyxcord/data/collectibles'
45
+ require 'onyxcord/data/primary_server'
46
+ require 'onyxcord/data/server_preview'
47
+ require 'onyxcord/data/call'
48
+ require 'onyxcord/data/snapshot'
49
+ require 'onyxcord/data/role_subscription'
50
+ require 'onyxcord/data/message_activity'
51
+ require 'onyxcord/data/team'
52
+ require 'onyxcord/data/install_params'
53
+ require 'onyxcord/data/role_connection_data'
54
+ require 'onyxcord/data/channel_tag'
55
+ require 'onyxcord/data/timestamp'
56
+ require 'onyxcord/data/scheduled_event'
57
+ require 'onyxcord/data/poll'
@@ -0,0 +1,246 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ # Custom errors raised in various places
5
+ module Errors
6
+ # Raised when authentication data is invalid or incorrect.
7
+ class InvalidAuthenticationError < RuntimeError
8
+ # Default message for this exception
9
+ def message
10
+ 'User login failed due to an invalid email or password!'
11
+ end
12
+ end
13
+
14
+ # Raised when a message is over the character limit
15
+ class MessageTooLong < RuntimeError; end
16
+
17
+ # Raised when the bot can't do something because its permissions on the server are insufficient
18
+ class NoPermission < RuntimeError; end
19
+
20
+ # Raised when the bot gets a HTTP 502 error, which is usually caused by Cloudflare.
21
+ class CloudflareError < RuntimeError; end
22
+
23
+ # Raised when using a webhook method without an associated token.
24
+ class UnauthorizedWebhook < RuntimeError; end
25
+
26
+ # Generic class for errors denoted by API error codes
27
+ class CodeError < RuntimeError
28
+ class << self
29
+ # @return [Integer] The error code represented by this error class.
30
+ attr_reader :code
31
+ end
32
+
33
+ # Create a new error with a particular message (the code should be defined by the class instance variable)
34
+ # @param message [String] the message to use
35
+ # @param errors [Hash] API errors
36
+ def initialize(message, errors = nil)
37
+ @message = message
38
+
39
+ @errors = errors ? flatten_errors(errors) : []
40
+ end
41
+
42
+ # @return [Integer] The error code represented by this error.
43
+ def code
44
+ self.class.code
45
+ end
46
+
47
+ # @return [String] A message including the message and flattened errors.
48
+ def full_message(*)
49
+ error_list = @errors.collect { |err| "\t- #{err}" }
50
+
51
+ "#{@message}\n#{error_list.join("\n")}"
52
+ end
53
+
54
+ # @return [String] This error's represented message
55
+ attr_reader :message
56
+
57
+ # @return [Hash] More precise errors
58
+ attr_reader :errors
59
+
60
+ private
61
+
62
+ # @!visibility hidden
63
+ # Flattens errors into a more easily read format.
64
+ # @example Flattening errors of a bad field
65
+ # flatten_errors(data['errors'])
66
+ # # => ["embed.fields[0].name: This field is required", "embed.fields[0].value: This field is required"]
67
+ def flatten_errors(err, prev_key = nil)
68
+ err.collect do |key, sub_err|
69
+ if prev_key
70
+ key = /\A\d+\Z/.match?(key) ? "#{prev_key}[#{key}]" : "#{prev_key}.#{key}"
71
+ end
72
+
73
+ if (errs = sub_err['_errors'])
74
+ "#{key}: #{errs.map { |e| e['message'] }.join(' ')}"
75
+ elsif sub_err['message'] || sub_err['code']
76
+ "#{"#{sub_err['code']}: " if sub_err['code']}#{err_msg}"
77
+ elsif sub_err.is_a? String
78
+ sub_err
79
+ else
80
+ flatten_errors(sub_err, key)
81
+ end
82
+ end.flatten
83
+ end
84
+ end
85
+
86
+ # Create a new code error class
87
+ # rubocop:disable Naming/MethodName
88
+ def self.Code(code)
89
+ classy = Class.new(CodeError)
90
+ classy.instance_variable_set(:@code, code)
91
+
92
+ @code_classes ||= {}
93
+ @code_classes[code] = classy
94
+
95
+ classy
96
+ end
97
+ # rubocop:enable Naming/MethodName
98
+
99
+ # @param code [Integer] The code to check
100
+ # @return [Class] the error class for the given code
101
+ def self.error_class_for(code)
102
+ @code_classes[code] || Code(code)
103
+ end
104
+
105
+ # Used when Discord doesn't provide a more specific code
106
+ UnknownError = Code(0)
107
+
108
+ # Unknown Account
109
+ UnknownAccount = Code(10_001)
110
+
111
+ # Unknown Application
112
+ UnknownApplication = Code(10_002)
113
+
114
+ # Unknown Channel
115
+ UnknownChannel = Code(10_003)
116
+
117
+ # Unknown Server
118
+ UnknownServer = Code(10_004)
119
+
120
+ # Unknown Integration
121
+ UnknownIntegration = Code(10_005)
122
+
123
+ # Unknown Invite
124
+ UnknownInvite = Code(10_006)
125
+
126
+ # Unknown Member
127
+ UnknownMember = Code(10_007)
128
+
129
+ # Unknown Message
130
+ UnknownMessage = Code(10_008)
131
+
132
+ # Unknown Overwrite
133
+ UnknownOverwrite = Code(10_009)
134
+
135
+ # Unknown Provider
136
+ UnknownProvider = Code(10_010)
137
+
138
+ # Unknown Role
139
+ UnknownRole = Code(10_011)
140
+
141
+ # Unknown Token
142
+ UnknownToken = Code(10_012)
143
+
144
+ # Unknown User
145
+ UnknownUser = Code(10_013)
146
+
147
+ # Unknown Emoji
148
+ UnknownEmoji = Code(10_014)
149
+
150
+ # Bots cannot use this endpoint
151
+ EndpointNotForBots = Code(20_001)
152
+
153
+ # Only bots can use this endpoint
154
+ EndpointOnlyForBots = Code(20_002)
155
+
156
+ # Maximum number of servers reached (100)
157
+ ServerLimitReached = Code(30_001)
158
+
159
+ # Maximum number of friends reached (1000)
160
+ FriendLimitReached = Code(30_002)
161
+
162
+ # Maximum number of pins reached (50)
163
+ PinLimitReached = Code(30_003)
164
+
165
+ # Maximum number of guild roles reached (250)
166
+ RoleLimitReached = Code(30_005)
167
+
168
+ # Too many reactions
169
+ ReactionLimitReached = Code(30_010)
170
+
171
+ # Maximum number of guild channels reached (500)
172
+ ChannelLimitReached = Code(30_013)
173
+
174
+ # Unauthorized
175
+ Unauthorized = Unauthorised = Code(40_001)
176
+
177
+ # Unable to bulk ban any users
178
+ UnableToBulkBanUsers = Code(500_000)
179
+
180
+ # Missing Access
181
+ MissingAccess = Code(50_001)
182
+
183
+ # Invalid Account Type
184
+ InvalidAccountType = Code(50_002)
185
+
186
+ # Cannot execute action on a DM channel
187
+ InvalidActionForDM = Code(50_003)
188
+
189
+ # Embed Disabled
190
+ EmbedDisabled = Code(50_004)
191
+
192
+ # Cannot edit a message authored by another user
193
+ MessageAuthoredByOtherUser = Code(50_005)
194
+
195
+ # Cannot send an empty message
196
+ MessageEmpty = Code(50_006)
197
+
198
+ # Cannot send messages to this user
199
+ NoMessagesToUser = Code(50_007)
200
+
201
+ # Cannot send messages in a voice channel
202
+ NoMessagesInVoiceChannel = Code(50_008)
203
+
204
+ # Channel verification level is too high
205
+ VerificationLevelTooHigh = Code(50_009)
206
+
207
+ # OAuth2 application does not have a bot
208
+ NoBotForApplication = Code(50_010)
209
+
210
+ # OAuth2 application limit reached
211
+ ApplicationLimitReached = Code(50_011)
212
+
213
+ # Invalid OAuth State
214
+ InvalidOAuthState = Code(50_012)
215
+
216
+ # Missing Permissions
217
+ MissingPermissions = Code(50_013)
218
+
219
+ # Invalid authentication token
220
+ InvalidAuthToken = Code(50_014)
221
+
222
+ # Note is too long
223
+ NoteTooLong = Code(50_015)
224
+
225
+ # Provided too few or too many messages to delete. Must provide at least 2 and fewer than 100 messages to delete.
226
+ InvalidBulkDeleteCount = Code(50_016)
227
+
228
+ # A message can only be pinned to the channel it was sent in
229
+ CannotPinInDifferentChannel = Code(50_019)
230
+
231
+ # Cannot execute action on a system message
232
+ InvalidActionForSystemMessage = Code(50_021)
233
+
234
+ # A message provided was too old to bulk delete
235
+ MessageTooOld = Code(50_034)
236
+
237
+ # Invalid Form Body
238
+ InvalidFormBody = Code(50_035)
239
+
240
+ # An invite was accepted to a guild the application's bot is not in
241
+ MissingBotMember = Code(50_036)
242
+
243
+ # Reaction Blocked
244
+ ReactionBlocked = Code(90_001)
245
+ end
246
+ end