discordrb 3.1.1 → 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.
- checksums.yaml +5 -5
- data/.circleci/config.yml +126 -0
- data/.codeclimate.yml +16 -0
- data/.github/CONTRIBUTING.md +13 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +25 -0
- data/.github/pull_request_template.md +37 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +39 -33
- data/.travis.yml +27 -2
- data/.yardopts +1 -1
- data/CHANGELOG.md +808 -208
- data/Gemfile +4 -1
- data/LICENSE.txt +1 -1
- data/README.md +108 -53
- data/Rakefile +14 -1
- data/bin/console +1 -0
- data/bin/travis_build_docs.sh +17 -0
- data/discordrb-webhooks.gemspec +26 -0
- data/discordrb.gemspec +24 -15
- data/lib/discordrb.rb +75 -2
- data/lib/discordrb/allowed_mentions.rb +36 -0
- data/lib/discordrb/api.rb +126 -27
- data/lib/discordrb/api/channel.rb +165 -43
- data/lib/discordrb/api/invite.rb +10 -7
- data/lib/discordrb/api/server.rb +240 -61
- data/lib/discordrb/api/user.rb +26 -24
- data/lib/discordrb/api/webhook.rb +83 -0
- data/lib/discordrb/await.rb +1 -2
- data/lib/discordrb/bot.rb +417 -149
- data/lib/discordrb/cache.rb +42 -10
- data/lib/discordrb/colour_rgb.rb +43 -0
- data/lib/discordrb/commands/command_bot.rb +186 -31
- data/lib/discordrb/commands/container.rb +30 -16
- data/lib/discordrb/commands/parser.rb +102 -47
- data/lib/discordrb/commands/rate_limiter.rb +18 -17
- data/lib/discordrb/container.rb +245 -41
- data/lib/discordrb/data.rb +27 -2511
- data/lib/discordrb/data/activity.rb +264 -0
- data/lib/discordrb/data/application.rb +50 -0
- data/lib/discordrb/data/attachment.rb +56 -0
- data/lib/discordrb/data/audit_logs.rb +345 -0
- data/lib/discordrb/data/channel.rb +849 -0
- data/lib/discordrb/data/embed.rb +251 -0
- data/lib/discordrb/data/emoji.rb +82 -0
- data/lib/discordrb/data/integration.rb +83 -0
- data/lib/discordrb/data/invite.rb +137 -0
- data/lib/discordrb/data/member.rb +297 -0
- data/lib/discordrb/data/message.rb +334 -0
- data/lib/discordrb/data/overwrite.rb +102 -0
- data/lib/discordrb/data/profile.rb +91 -0
- data/lib/discordrb/data/reaction.rb +33 -0
- data/lib/discordrb/data/recipient.rb +34 -0
- data/lib/discordrb/data/role.rb +191 -0
- data/lib/discordrb/data/server.rb +1002 -0
- data/lib/discordrb/data/user.rb +204 -0
- data/lib/discordrb/data/voice_region.rb +45 -0
- data/lib/discordrb/data/voice_state.rb +41 -0
- data/lib/discordrb/data/webhook.rb +145 -0
- data/lib/discordrb/errors.rb +36 -2
- data/lib/discordrb/events/bans.rb +7 -5
- data/lib/discordrb/events/channels.rb +2 -0
- data/lib/discordrb/events/generic.rb +19 -3
- data/lib/discordrb/events/guilds.rb +129 -6
- data/lib/discordrb/events/invites.rb +125 -0
- data/lib/discordrb/events/members.rb +6 -2
- data/lib/discordrb/events/message.rb +86 -36
- data/lib/discordrb/events/presence.rb +23 -16
- data/lib/discordrb/events/raw.rb +47 -0
- data/lib/discordrb/events/reactions.rb +159 -0
- data/lib/discordrb/events/roles.rb +7 -6
- data/lib/discordrb/events/typing.rb +9 -5
- data/lib/discordrb/events/voice_server_update.rb +47 -0
- data/lib/discordrb/events/voice_state_update.rb +29 -9
- data/lib/discordrb/events/webhooks.rb +64 -0
- data/lib/discordrb/gateway.rb +219 -88
- data/lib/discordrb/id_object.rb +39 -0
- data/lib/discordrb/light.rb +1 -1
- data/lib/discordrb/light/integrations.rb +1 -1
- data/lib/discordrb/light/light_bot.rb +1 -1
- data/lib/discordrb/logger.rb +12 -11
- data/lib/discordrb/paginator.rb +57 -0
- data/lib/discordrb/permissions.rb +148 -14
- data/lib/discordrb/version.rb +1 -1
- data/lib/discordrb/voice/encoder.rb +14 -15
- data/lib/discordrb/voice/network.rb +86 -45
- data/lib/discordrb/voice/sodium.rb +96 -0
- data/lib/discordrb/voice/voice_bot.rb +52 -40
- data/lib/discordrb/webhooks.rb +12 -0
- data/lib/discordrb/websocket.rb +2 -2
- metadata +137 -34
@@ -0,0 +1,1002 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Discordrb
|
4
|
+
# Basic attributes a server should have
|
5
|
+
module ServerAttributes
|
6
|
+
# @return [String] this server's name.
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
# @return [String] the hexadecimal ID used to identify this server's icon.
|
10
|
+
attr_reader :icon_id
|
11
|
+
|
12
|
+
# Utility function to get the URL for the icon image
|
13
|
+
# @return [String] the URL to the icon image
|
14
|
+
def icon_url
|
15
|
+
return nil unless @icon_id
|
16
|
+
|
17
|
+
API.icon_url(@id, @icon_id)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# A server on Discord
|
22
|
+
class Server
|
23
|
+
include IDObject
|
24
|
+
include ServerAttributes
|
25
|
+
|
26
|
+
# @return [String] the ID of the region the server is on (e.g. `amsterdam`).
|
27
|
+
attr_reader :region_id
|
28
|
+
|
29
|
+
# @return [Array<Channel>] an array of all the channels (text and voice) on this server.
|
30
|
+
attr_reader :channels
|
31
|
+
|
32
|
+
# @return [Array<Role>] an array of all the roles created on this server.
|
33
|
+
attr_reader :roles
|
34
|
+
|
35
|
+
# @return [Hash<Integer => Emoji>] a hash of all the emoji available on this server.
|
36
|
+
attr_reader :emoji
|
37
|
+
alias_method :emojis, :emoji
|
38
|
+
|
39
|
+
# @return [true, false] whether or not this server is large (members > 100). If it is,
|
40
|
+
# it means the members list may be inaccurate for a couple seconds after starting up the bot.
|
41
|
+
attr_reader :large
|
42
|
+
alias_method :large?, :large
|
43
|
+
|
44
|
+
# @return [Array<Symbol>] the features of the server (eg. "INVITE_SPLASH")
|
45
|
+
attr_reader :features
|
46
|
+
|
47
|
+
# @return [Integer] the absolute number of members on this server, offline or not.
|
48
|
+
attr_reader :member_count
|
49
|
+
|
50
|
+
# @return [Integer] the amount of time after which a voice user gets moved into the AFK channel, in seconds.
|
51
|
+
attr_reader :afk_timeout
|
52
|
+
|
53
|
+
# @return [Hash<Integer => VoiceState>] the hash (user ID => voice state) of voice states of members on this server
|
54
|
+
attr_reader :voice_states
|
55
|
+
|
56
|
+
# The server's amount of Nitro boosters.
|
57
|
+
# @return [Integer] the amount of boosters, 0 if no one has boosted.
|
58
|
+
attr_reader :booster_count
|
59
|
+
|
60
|
+
# The server's Nitro boost level.
|
61
|
+
# @return [Integer] the boost level, 0 if no level.
|
62
|
+
attr_reader :boost_level
|
63
|
+
|
64
|
+
# @!visibility private
|
65
|
+
def initialize(data, bot)
|
66
|
+
@bot = bot
|
67
|
+
@owner_id = data['owner_id'].to_i
|
68
|
+
@id = data['id'].to_i
|
69
|
+
|
70
|
+
process_channels(data['channels'])
|
71
|
+
update_data(data)
|
72
|
+
|
73
|
+
@large = data['large']
|
74
|
+
@member_count = data['member_count']
|
75
|
+
@splash_id = nil
|
76
|
+
@banner_id = nil
|
77
|
+
@features = data['features'].map { |element| element.downcase.to_sym }
|
78
|
+
@members = {}
|
79
|
+
@voice_states = {}
|
80
|
+
@emoji = {}
|
81
|
+
|
82
|
+
process_roles(data['roles'])
|
83
|
+
process_emoji(data['emojis'])
|
84
|
+
process_members(data['members'])
|
85
|
+
process_presences(data['presences'])
|
86
|
+
process_voice_states(data['voice_states'])
|
87
|
+
|
88
|
+
# Whether this server's members have been chunked (resolved using op 8 and GUILD_MEMBERS_CHUNK) yet
|
89
|
+
@chunked = false
|
90
|
+
@processed_chunk_members = 0
|
91
|
+
|
92
|
+
@booster_count = data['premium_subscription_count'] || 0
|
93
|
+
@boost_level = data['premium_tier']
|
94
|
+
end
|
95
|
+
|
96
|
+
# @return [Member] The server owner.
|
97
|
+
def owner
|
98
|
+
@owner ||= member(@owner_id)
|
99
|
+
end
|
100
|
+
|
101
|
+
# The default channel is the text channel on this server with the highest position
|
102
|
+
# that the bot has Read Messages permission on.
|
103
|
+
# @param send_messages [true, false] whether to additionally consider if the bot has Send Messages permission
|
104
|
+
# @return [Channel, nil] The default channel on this server, or `nil` if there are no channels that the bot can read.
|
105
|
+
def default_channel(send_messages = false)
|
106
|
+
bot_member = member(@bot.profile)
|
107
|
+
text_channels.sort_by { |e| [e.position, e.id] }.find do |e|
|
108
|
+
if send_messages
|
109
|
+
bot_member.can_read_messages?(e) && bot_member.can_send_messages?(e)
|
110
|
+
else
|
111
|
+
bot_member.can_read_messages?(e)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
alias_method :general_channel, :default_channel
|
117
|
+
|
118
|
+
# @return [Role] The @everyone role on this server
|
119
|
+
def everyone_role
|
120
|
+
role(@id)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Gets a role on this server based on its ID.
|
124
|
+
# @param id [String, Integer] The role ID to look for.
|
125
|
+
# @return [Role, nil] The role identified by the ID, or `nil` if it couldn't be found.
|
126
|
+
def role(id)
|
127
|
+
id = id.resolve_id
|
128
|
+
@roles.find { |e| e.id == id }
|
129
|
+
end
|
130
|
+
|
131
|
+
# Gets a member on this server based on user ID
|
132
|
+
# @param id [Integer] The user ID to look for
|
133
|
+
# @param request [true, false] Whether the member should be requested from Discord if it's not cached
|
134
|
+
def member(id, request = true)
|
135
|
+
id = id.resolve_id
|
136
|
+
return @members[id] if member_cached?(id)
|
137
|
+
return nil unless request
|
138
|
+
|
139
|
+
member = @bot.member(self, id)
|
140
|
+
@members[id] = member unless member.nil?
|
141
|
+
rescue StandardError
|
142
|
+
nil
|
143
|
+
end
|
144
|
+
|
145
|
+
# @return [Array<Member>] an array of all the members on this server.
|
146
|
+
def members
|
147
|
+
return @members.values if @chunked
|
148
|
+
|
149
|
+
@bot.debug("Members for server #{@id} not chunked yet - initiating")
|
150
|
+
@bot.request_chunks(@id)
|
151
|
+
sleep 0.05 until @chunked
|
152
|
+
@members.values
|
153
|
+
end
|
154
|
+
|
155
|
+
alias_method :users, :members
|
156
|
+
|
157
|
+
# @return [Array<Member>] an array of all the bot members on this server.
|
158
|
+
def bot_members
|
159
|
+
members.select(&:bot_account?)
|
160
|
+
end
|
161
|
+
|
162
|
+
# @return [Array<Member>] an array of all the non bot members on this server.
|
163
|
+
def non_bot_members
|
164
|
+
members.reject(&:bot_account?)
|
165
|
+
end
|
166
|
+
|
167
|
+
# @return [Member] the bot's own `Member` on this server
|
168
|
+
def bot
|
169
|
+
member(@bot.profile)
|
170
|
+
end
|
171
|
+
|
172
|
+
# @return [Array<Integration>] an array of all the integrations connected to this server.
|
173
|
+
def integrations
|
174
|
+
integration = JSON.parse(API::Server.integrations(@bot.token, @id))
|
175
|
+
integration.map { |element| Integration.new(element, @bot, self) }
|
176
|
+
end
|
177
|
+
|
178
|
+
# @param action [Symbol] The action to only include.
|
179
|
+
# @param user [User, String, Integer] The user, or their ID, to filter entries to.
|
180
|
+
# @param limit [Integer] The amount of entries to limit it to.
|
181
|
+
# @param before [Entry, String, Integer] The entry, or its ID, to use to not include all entries after it.
|
182
|
+
# @return [AuditLogs] The server's audit logs.
|
183
|
+
def audit_logs(action: nil, user: nil, limit: 50, before: nil)
|
184
|
+
raise 'Invalid audit log action!' if action && AuditLogs::ACTIONS.key(action).nil?
|
185
|
+
|
186
|
+
action = AuditLogs::ACTIONS.key(action)
|
187
|
+
user = user.resolve_id if user
|
188
|
+
before = before.resolve_id if before
|
189
|
+
AuditLogs.new(self, @bot, JSON.parse(API::Server.audit_logs(@bot.token, @id, limit, user, action, before)))
|
190
|
+
end
|
191
|
+
|
192
|
+
# Cache @embed
|
193
|
+
# @note For internal use only
|
194
|
+
# @!visibility private
|
195
|
+
def cache_embed_data
|
196
|
+
data = JSON.parse(API::Server.embed(@bot.token, @id))
|
197
|
+
@embed_enabled = data['enabled']
|
198
|
+
@embed_channel_id = data['channel_id']
|
199
|
+
end
|
200
|
+
|
201
|
+
# @return [true, false] whether or not the server has widget enabled
|
202
|
+
def embed_enabled?
|
203
|
+
cache_embed_data if @embed_enabled.nil?
|
204
|
+
@embed_enabled
|
205
|
+
end
|
206
|
+
alias_method :widget_enabled, :embed_enabled?
|
207
|
+
alias_method :widget?, :embed_enabled?
|
208
|
+
alias_method :embed?, :embed_enabled?
|
209
|
+
|
210
|
+
# @return [Channel, nil] the channel the server embed will make an invite for.
|
211
|
+
def embed_channel
|
212
|
+
cache_embed_data if @embed_enabled.nil?
|
213
|
+
@bot.channel(@embed_channel_id) if @embed_channel_id
|
214
|
+
end
|
215
|
+
alias_method :widget_channel, :embed_channel
|
216
|
+
|
217
|
+
# Sets whether this server's embed (widget) is enabled
|
218
|
+
# @param value [true, false]
|
219
|
+
def embed_enabled=(value)
|
220
|
+
modify_embed(value, embed_channel)
|
221
|
+
end
|
222
|
+
|
223
|
+
alias_method :widget_enabled=, :embed_enabled=
|
224
|
+
|
225
|
+
# Sets whether this server's embed (widget) is enabled
|
226
|
+
# @param value [true, false]
|
227
|
+
# @param reason [String, nil] the reason to be shown in the audit log for this action
|
228
|
+
def set_embed_enabled(value, reason = nil)
|
229
|
+
modify_embed(value, embed_channel, reason)
|
230
|
+
end
|
231
|
+
|
232
|
+
alias_method :set_widget_enabled, :set_embed_enabled
|
233
|
+
|
234
|
+
# Changes the channel on the server's embed (widget)
|
235
|
+
# @param channel [Channel, String, Integer] the channel, or its ID, to be referenced by the embed
|
236
|
+
def embed_channel=(channel)
|
237
|
+
modify_embed(embed?, channel)
|
238
|
+
end
|
239
|
+
|
240
|
+
alias_method :widget_channel=, :embed_channel=
|
241
|
+
|
242
|
+
# Changes the channel on the server's embed (widget)
|
243
|
+
# @param channel [Channel, String, Integer] the channel, or its ID, to be referenced by the embed
|
244
|
+
# @param reason [String, nil] the reason to be shown in the audit log for this action
|
245
|
+
def set_embed_channel(channel, reason = nil)
|
246
|
+
modify_embed(embed?, channel, reason)
|
247
|
+
end
|
248
|
+
|
249
|
+
alias_method :set_widget_channel, :set_embed_channel
|
250
|
+
|
251
|
+
# Changes the channel on the server's embed (widget), and sets whether it is enabled.
|
252
|
+
# @param enabled [true, false] whether the embed (widget) is enabled
|
253
|
+
# @param channel [Channel, String, Integer] the channel, or its ID, to be referenced by the embed
|
254
|
+
# @param reason [String, nil] the reason to be shown in the audit log for this action
|
255
|
+
def modify_embed(enabled, channel, reason = nil)
|
256
|
+
cache_embed_data if @embed_enabled.nil?
|
257
|
+
channel_id = channel ? channel.resolve_id : @embed_channel_id
|
258
|
+
response = JSON.parse(API::Server.modify_embed(@bot.token, @id, enabled, channel_id, reason))
|
259
|
+
@embed_enabled = response['enabled']
|
260
|
+
@embed_channel_id = response['channel_id']
|
261
|
+
end
|
262
|
+
|
263
|
+
alias_method :modify_widget, :modify_embed
|
264
|
+
|
265
|
+
# @param include_idle [true, false] Whether to count idle members as online.
|
266
|
+
# @param include_bots [true, false] Whether to include bot accounts in the count.
|
267
|
+
# @return [Array<Member>] an array of online members on this server.
|
268
|
+
def online_members(include_idle: false, include_bots: true)
|
269
|
+
@members.values.select do |e|
|
270
|
+
((include_idle ? e.idle? : false) || e.online?) && (include_bots ? true : !e.bot_account?)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
alias_method :online_users, :online_members
|
275
|
+
|
276
|
+
# Adds a member to this guild that has granted this bot's application an OAuth2 access token
|
277
|
+
# with the `guilds.join` scope.
|
278
|
+
# For more information about Discord's OAuth2 implementation, see: https://discord.com/developers/docs/topics/oauth2
|
279
|
+
# @note Your bot must be present in this server, and have permission to create instant invites for this to work.
|
280
|
+
# @param user [User, String, Integer] the user, or ID of the user to add to this server
|
281
|
+
# @param access_token [String] the OAuth2 Bearer token that has been granted the `guilds.join` scope
|
282
|
+
# @param nick [String] the nickname to give this member upon joining
|
283
|
+
# @param roles [Role, Array<Role, String, Integer>] the role (or roles) to give this member upon joining
|
284
|
+
# @param deaf [true, false] whether this member will be server deafened upon joining
|
285
|
+
# @param mute [true, false] whether this member will be server muted upon joining
|
286
|
+
# @return [Member, nil] the created member, or `nil` if the user is already a member of this server.
|
287
|
+
def add_member_using_token(user, access_token, nick: nil, roles: [], deaf: false, mute: false)
|
288
|
+
user_id = user.resolve_id
|
289
|
+
roles = roles.is_a?(Array) ? roles.map(&:resolve_id) : [roles.resolve_id]
|
290
|
+
response = API::Server.add_member(@bot.token, @id, user_id, access_token, nick, roles, deaf, mute)
|
291
|
+
return nil if response.empty?
|
292
|
+
|
293
|
+
add_member Member.new(JSON.parse(response), self, @bot)
|
294
|
+
end
|
295
|
+
|
296
|
+
# Returns the amount of members that are candidates for pruning
|
297
|
+
# @param days [Integer] the number of days to consider for inactivity
|
298
|
+
# @return [Integer] number of members to be removed
|
299
|
+
# @raise [ArgumentError] if days is not between 1 and 30 (inclusive)
|
300
|
+
def prune_count(days)
|
301
|
+
raise ArgumentError, 'Days must be between 1 and 30' unless days.between?(1, 30)
|
302
|
+
|
303
|
+
response = JSON.parse API::Server.prune_count(@bot.token, @id, days)
|
304
|
+
response['pruned']
|
305
|
+
end
|
306
|
+
|
307
|
+
# Prunes (kicks) an amount of members for inactivity
|
308
|
+
# @param days [Integer] the number of days to consider for inactivity (between 1 and 30)
|
309
|
+
# @param reason [String] The reason the for the prune.
|
310
|
+
# @return [Integer] the number of members removed at the end of the operation
|
311
|
+
# @raise [ArgumentError] if days is not between 1 and 30 (inclusive)
|
312
|
+
def begin_prune(days, reason = nil)
|
313
|
+
raise ArgumentError, 'Days must be between 1 and 30' unless days.between?(1, 30)
|
314
|
+
|
315
|
+
response = JSON.parse API::Server.begin_prune(@bot.token, @id, days, reason)
|
316
|
+
response['pruned']
|
317
|
+
end
|
318
|
+
|
319
|
+
alias_method :prune, :begin_prune
|
320
|
+
|
321
|
+
# @return [Array<Channel>] an array of text channels on this server
|
322
|
+
def text_channels
|
323
|
+
@channels.select(&:text?)
|
324
|
+
end
|
325
|
+
|
326
|
+
# @return [Array<Channel>] an array of voice channels on this server
|
327
|
+
def voice_channels
|
328
|
+
@channels.select(&:voice?)
|
329
|
+
end
|
330
|
+
|
331
|
+
# @return [Array<Channel>] an array of category channels on this server
|
332
|
+
def categories
|
333
|
+
@channels.select(&:category?)
|
334
|
+
end
|
335
|
+
|
336
|
+
# @return [Array<Channel>] an array of channels on this server that are not in a category
|
337
|
+
def orphan_channels
|
338
|
+
@channels.reject { |c| c.parent || c.category? }
|
339
|
+
end
|
340
|
+
|
341
|
+
# @return [String, nil] the widget URL to the server that displays the amount of online members in a
|
342
|
+
# stylish way. `nil` if the widget is not enabled.
|
343
|
+
def widget_url
|
344
|
+
update_data if @embed_enabled.nil?
|
345
|
+
return unless @embed_enabled
|
346
|
+
|
347
|
+
API.widget_url(@id)
|
348
|
+
end
|
349
|
+
|
350
|
+
# @param style [Symbol] The style the picture should have. Possible styles are:
|
351
|
+
# * `:banner1` creates a rectangular image with the server name, member count and icon, a "Powered by Discord" message on the bottom and an arrow on the right.
|
352
|
+
# * `:banner2` creates a less tall rectangular image that has the same information as `banner1`, but the Discord logo on the right - together with the arrow and separated by a diagonal separator.
|
353
|
+
# * `:banner3` creates an image similar in size to `banner1`, but it has the arrow in the bottom part, next to the Discord logo and with a "Chat now" text.
|
354
|
+
# * `:banner4` creates a tall, almost square, image that prominently features the Discord logo at the top and has a "Join my server" in a pill-style button on the bottom. The information about the server is in the same format as the other three `banner` styles.
|
355
|
+
# * `:shield` creates a very small, long rectangle, of the style you'd find at the top of GitHub `README.md` files. It features a small version of the Discord logo at the left and the member count at the right.
|
356
|
+
# @return [String, nil] the widget banner URL to the server that displays the amount of online members,
|
357
|
+
# server icon and server name in a stylish way. `nil` if the widget is not enabled.
|
358
|
+
def widget_banner_url(style)
|
359
|
+
update_data if @embed_enabled.nil?
|
360
|
+
return unless @embed_enabled
|
361
|
+
|
362
|
+
API.widget_url(@id, style)
|
363
|
+
end
|
364
|
+
|
365
|
+
# @return [String] the hexadecimal ID used to identify this server's splash image for their VIP invite page.
|
366
|
+
def splash_id
|
367
|
+
@splash_id ||= JSON.parse(API::Server.resolve(@bot.token, @id))['splash']
|
368
|
+
end
|
369
|
+
alias splash_hash splash_id
|
370
|
+
|
371
|
+
# @return [String, nil] the splash image URL for the server's VIP invite page.
|
372
|
+
# `nil` if there is no splash image.
|
373
|
+
def splash_url
|
374
|
+
splash_id if @splash_id.nil?
|
375
|
+
return nil unless @splash_id
|
376
|
+
|
377
|
+
API.splash_url(@id, @splash_id)
|
378
|
+
end
|
379
|
+
|
380
|
+
# @return [String] the hexadecimal ID used to identify this server's banner image, shown by the server name.
|
381
|
+
def banner_id
|
382
|
+
@banner_id ||= JSON.parse(API::Server.resolve(@bot.token, @id))['banner']
|
383
|
+
end
|
384
|
+
|
385
|
+
# @return [String, nil] the banner image URL for the server's banner image, or
|
386
|
+
# `nil` if there is no banner image.
|
387
|
+
def banner_url
|
388
|
+
banner_id if @banner_id.nil?
|
389
|
+
return unless banner_id
|
390
|
+
|
391
|
+
API.banner_url(@id, @banner_id)
|
392
|
+
end
|
393
|
+
|
394
|
+
# @return [String] a URL that a user can use to navigate to this server in the client
|
395
|
+
def link
|
396
|
+
"https://discord.com/channels/#{@id}"
|
397
|
+
end
|
398
|
+
|
399
|
+
alias_method :jump_link, :link
|
400
|
+
|
401
|
+
# Adds a role to the role cache
|
402
|
+
# @note For internal use only
|
403
|
+
# @!visibility private
|
404
|
+
def add_role(role)
|
405
|
+
@roles << role
|
406
|
+
end
|
407
|
+
|
408
|
+
# Removes a role from the role cache
|
409
|
+
# @note For internal use only
|
410
|
+
# @!visibility private
|
411
|
+
def delete_role(role_id)
|
412
|
+
@roles.reject! { |r| r.id == role_id }
|
413
|
+
@members.each do |_, member|
|
414
|
+
new_roles = member.roles.reject { |r| r.id == role_id }
|
415
|
+
member.update_roles(new_roles)
|
416
|
+
end
|
417
|
+
@channels.each do |channel|
|
418
|
+
overwrites = channel.permission_overwrites.reject { |id, _| id == role_id }
|
419
|
+
channel.update_overwrites(overwrites)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
# Updates the positions of all roles on the server
|
424
|
+
# @note For internal use only
|
425
|
+
# @!visibility private
|
426
|
+
def update_role_positions(role_positions)
|
427
|
+
response = JSON.parse(API::Server.update_role_positions(@bot.token, @id, role_positions))
|
428
|
+
response.each do |data|
|
429
|
+
updated_role = Role.new(data, @bot, self)
|
430
|
+
role(updated_role.id).update_from(updated_role)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
# Adds a member to the member cache.
|
435
|
+
# @note For internal use only
|
436
|
+
# @!visibility private
|
437
|
+
def add_member(member)
|
438
|
+
@member_count += 1
|
439
|
+
@members[member.id] = member
|
440
|
+
end
|
441
|
+
|
442
|
+
# Removes a member from the member cache.
|
443
|
+
# @note For internal use only
|
444
|
+
# @!visibility private
|
445
|
+
def delete_member(user_id)
|
446
|
+
@members.delete(user_id)
|
447
|
+
@member_count -= 1
|
448
|
+
end
|
449
|
+
|
450
|
+
# Checks whether a member is cached
|
451
|
+
# @note For internal use only
|
452
|
+
# @!visibility private
|
453
|
+
def member_cached?(user_id)
|
454
|
+
@members.include?(user_id)
|
455
|
+
end
|
456
|
+
|
457
|
+
# Adds a member to the cache
|
458
|
+
# @note For internal use only
|
459
|
+
# @!visibility private
|
460
|
+
def cache_member(member)
|
461
|
+
@members[member.id] = member
|
462
|
+
end
|
463
|
+
|
464
|
+
# Updates a member's voice state
|
465
|
+
# @note For internal use only
|
466
|
+
# @!visibility private
|
467
|
+
def update_voice_state(data)
|
468
|
+
user_id = data['user_id'].to_i
|
469
|
+
|
470
|
+
if data['channel_id']
|
471
|
+
unless @voice_states[user_id]
|
472
|
+
# Create a new voice state for the user
|
473
|
+
@voice_states[user_id] = VoiceState.new(user_id)
|
474
|
+
end
|
475
|
+
|
476
|
+
# Update the existing voice state (or the one we just created)
|
477
|
+
channel = @channels_by_id[data['channel_id'].to_i]
|
478
|
+
@voice_states[user_id].update(
|
479
|
+
channel,
|
480
|
+
data['mute'],
|
481
|
+
data['deaf'],
|
482
|
+
data['self_mute'],
|
483
|
+
data['self_deaf']
|
484
|
+
)
|
485
|
+
else
|
486
|
+
# The user is not in a voice channel anymore, so delete its voice state
|
487
|
+
@voice_states.delete(user_id)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
# Creates a channel on this server with the given name.
|
492
|
+
# @note If parent is provided, permission overwrites have the follow behavior:
|
493
|
+
#
|
494
|
+
# 1. If overwrites is null, the new channel inherits the parent's permissions.
|
495
|
+
# 2. If overwrites is [], the new channel inherits the parent's permissions.
|
496
|
+
# 3. If you supply one or more overwrites, the channel will be created with those permissions and ignore the parents.
|
497
|
+
#
|
498
|
+
# @param name [String] Name of the channel to create
|
499
|
+
# @param type [Integer, Symbol] Type of channel to create (0: text, 2: voice, 4: category, 5: news, 6: store)
|
500
|
+
# @param topic [String] the topic of this channel, if it will be a text channel
|
501
|
+
# @param bitrate [Integer] the bitrate of this channel, if it will be a voice channel
|
502
|
+
# @param user_limit [Integer] the user limit of this channel, if it will be a voice channel
|
503
|
+
# @param permission_overwrites [Array<Hash>, Array<Overwrite>] permission overwrites for this channel
|
504
|
+
# @param parent [Channel, String, Integer] parent category, or its ID, for this channel to be created in.
|
505
|
+
# @param nsfw [true, false] whether this channel should be created as nsfw
|
506
|
+
# @param rate_limit_per_user [Integer] how many seconds users need to wait in between messages.
|
507
|
+
# @param reason [String] The reason the for the creation of this channel.
|
508
|
+
# @return [Channel] the created channel.
|
509
|
+
# @raise [ArgumentError] if type is not 0 (text), 2 (voice), 4 (category), 5 (news), or 6 (store)
|
510
|
+
def create_channel(name, type = 0, topic: nil, bitrate: nil, user_limit: nil, permission_overwrites: nil, parent: nil, nsfw: false, rate_limit_per_user: nil, position: nil, reason: nil)
|
511
|
+
type = Channel::TYPES[type] if type.is_a?(Symbol)
|
512
|
+
raise ArgumentError, 'Channel type must be either 0 (text), 2 (voice), 4 (category), news (5), or store (6)!' unless [0, 2, 4, 5, 6].include?(type)
|
513
|
+
|
514
|
+
permission_overwrites.map! { |e| e.is_a?(Overwrite) ? e.to_hash : e } if permission_overwrites.is_a?(Array)
|
515
|
+
parent_id = parent.respond_to?(:resolve_id) ? parent.resolve_id : nil
|
516
|
+
response = API::Server.create_channel(@bot.token, @id, name, type, topic, bitrate, user_limit, permission_overwrites, parent_id, nsfw, rate_limit_per_user, position, reason)
|
517
|
+
Channel.new(JSON.parse(response), @bot)
|
518
|
+
end
|
519
|
+
|
520
|
+
# Creates a role on this server which can then be modified. It will be initialized
|
521
|
+
# with the regular role defaults the client uses unless specified, i.e. name is "new role",
|
522
|
+
# permissions are the default, colour is the default etc.
|
523
|
+
# @param name [String] Name of the role to create
|
524
|
+
# @param colour [Integer, ColourRGB, #combined] The roles colour
|
525
|
+
# @param hoist [true, false]
|
526
|
+
# @param mentionable [true, false]
|
527
|
+
# @param permissions [Integer, Array<Symbol>, Permissions, #bits] The permissions to write to the new role.
|
528
|
+
# @param reason [String] The reason the for the creation of this role.
|
529
|
+
# @return [Role] the created role.
|
530
|
+
def create_role(name: 'new role', colour: 0, hoist: false, mentionable: false, permissions: 104_324_161, reason: nil)
|
531
|
+
colour = colour.respond_to?(:combined) ? colour.combined : colour
|
532
|
+
|
533
|
+
permissions = if permissions.is_a?(Array)
|
534
|
+
Permissions.bits(permissions)
|
535
|
+
elsif permissions.respond_to?(:bits)
|
536
|
+
permissions.bits
|
537
|
+
else
|
538
|
+
permissions
|
539
|
+
end
|
540
|
+
|
541
|
+
response = API::Server.create_role(@bot.token, @id, name, colour, hoist, mentionable, permissions, reason)
|
542
|
+
|
543
|
+
role = Role.new(JSON.parse(response), @bot, self)
|
544
|
+
@roles << role
|
545
|
+
role
|
546
|
+
end
|
547
|
+
|
548
|
+
# Adds a new custom emoji on this server.
|
549
|
+
# @param name [String] The name of emoji to create.
|
550
|
+
# @param image [String, #read] A base64 encoded string with the image data, or an object that responds to `#read`, such as `File`.
|
551
|
+
# @param roles [Array<Role, String, Integer>] An array of roles, or role IDs to be whitelisted for this emoji.
|
552
|
+
# @param reason [String] The reason the for the creation of this emoji.
|
553
|
+
# @return [Emoji] The emoji that has been added.
|
554
|
+
def add_emoji(name, image, roles = [], reason: nil)
|
555
|
+
image_string = image
|
556
|
+
if image.respond_to? :read
|
557
|
+
image_string = 'data:image/jpg;base64,'
|
558
|
+
image_string += Base64.strict_encode64(image.read)
|
559
|
+
end
|
560
|
+
|
561
|
+
data = JSON.parse(API::Server.add_emoji(@bot.token, @id, image_string, name, roles.map(&:resolve_id), reason))
|
562
|
+
new_emoji = Emoji.new(data, @bot, self)
|
563
|
+
@emoji[new_emoji.id] = new_emoji
|
564
|
+
end
|
565
|
+
|
566
|
+
# Delete a custom emoji on this server
|
567
|
+
# @param emoji [Emoji, String, Integer] The emoji or emoji ID to be deleted.
|
568
|
+
# @param reason [String] The reason the for the deletion of this emoji.
|
569
|
+
def delete_emoji(emoji, reason: nil)
|
570
|
+
API::Server.delete_emoji(@bot.token, @id, emoji.resolve_id, reason)
|
571
|
+
end
|
572
|
+
|
573
|
+
# Changes the name and/or role whitelist of an emoji on this server.
|
574
|
+
# @param emoji [Emoji, String, Integer] The emoji or emoji ID to edit.
|
575
|
+
# @param name [String] The new name for the emoji.
|
576
|
+
# @param roles [Array<Role, String, Integer>] A new array of roles, or role IDs, to whitelist.
|
577
|
+
# @param reason [String] The reason for the editing of this emoji.
|
578
|
+
# @return [Emoji] The edited emoji.
|
579
|
+
def edit_emoji(emoji, name: nil, roles: nil, reason: nil)
|
580
|
+
emoji = @emoji[emoji.resolve_id]
|
581
|
+
data = JSON.parse(API::Server.edit_emoji(@bot.token, @id, emoji.resolve_id, name || emoji.name, (roles || emoji.roles).map(&:resolve_id), reason))
|
582
|
+
new_emoji = Emoji.new(data, @bot, self)
|
583
|
+
@emoji[new_emoji.id] = new_emoji
|
584
|
+
end
|
585
|
+
|
586
|
+
# The amount of emoji the server can have, based on its current Nitro Boost Level.
|
587
|
+
# @return [Integer] the max amount of emoji
|
588
|
+
def max_emoji
|
589
|
+
case @level
|
590
|
+
when 1
|
591
|
+
100
|
592
|
+
when 2
|
593
|
+
150
|
594
|
+
when 3
|
595
|
+
250
|
596
|
+
else
|
597
|
+
50
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
601
|
+
# @return [Array<ServerBan>] a list of banned users on this server and the reason they were banned.
|
602
|
+
def bans
|
603
|
+
response = JSON.parse(API::Server.bans(@bot.token, @id))
|
604
|
+
response.map do |e|
|
605
|
+
ServerBan.new(self, User.new(e['user'], @bot), e['reason'])
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
# Bans a user from this server.
|
610
|
+
# @param user [User, String, Integer] The user to ban.
|
611
|
+
# @param message_days [Integer] How many days worth of messages sent by the user should be deleted.
|
612
|
+
# @param reason [String] The reason the user is being banned.
|
613
|
+
def ban(user, message_days = 0, reason: nil)
|
614
|
+
API::Server.ban_user(@bot.token, @id, user.resolve_id, message_days, reason)
|
615
|
+
end
|
616
|
+
|
617
|
+
# Unbans a previously banned user from this server.
|
618
|
+
# @param user [User, String, Integer] The user to unban.
|
619
|
+
# @param reason [String] The reason the user is being unbanned.
|
620
|
+
def unban(user, reason = nil)
|
621
|
+
API::Server.unban_user(@bot.token, @id, user.resolve_id, reason)
|
622
|
+
end
|
623
|
+
|
624
|
+
# Kicks a user from this server.
|
625
|
+
# @param user [User, String, Integer] The user to kick.
|
626
|
+
# @param reason [String] The reason the user is being kicked.
|
627
|
+
def kick(user, reason = nil)
|
628
|
+
API::Server.remove_member(@bot.token, @id, user.resolve_id, reason)
|
629
|
+
end
|
630
|
+
|
631
|
+
# Forcibly moves a user into a different voice channel. Only works if the bot has the permission needed.
|
632
|
+
# @param user [User, String, Integer] The user to move.
|
633
|
+
# @param channel [Channel, String, Integer] The voice channel to move into.
|
634
|
+
def move(user, channel)
|
635
|
+
API::Server.update_member(@bot.token, @id, user.resolve_id, channel_id: channel.resolve_id)
|
636
|
+
end
|
637
|
+
|
638
|
+
# Deletes this server. Be aware that this is permanent and impossible to undo, so be careful!
|
639
|
+
def delete
|
640
|
+
API::Server.delete(@bot.token, @id)
|
641
|
+
end
|
642
|
+
|
643
|
+
# Leave the server.
|
644
|
+
def leave
|
645
|
+
API::User.leave_server(@bot.token, @id)
|
646
|
+
end
|
647
|
+
|
648
|
+
# Transfers server ownership to another user.
|
649
|
+
# @param user [User, String, Integer] The user who should become the new owner.
|
650
|
+
def owner=(user)
|
651
|
+
API::Server.transfer_ownership(@bot.token, @id, user.resolve_id)
|
652
|
+
end
|
653
|
+
|
654
|
+
# Sets the server's name.
|
655
|
+
# @param name [String] The new server name.
|
656
|
+
def name=(name)
|
657
|
+
update_server_data(name: name)
|
658
|
+
end
|
659
|
+
|
660
|
+
# @return [Array<VoiceRegion>] collection of available voice regions to this guild
|
661
|
+
def available_voice_regions
|
662
|
+
return @available_voice_regions if @available_voice_regions
|
663
|
+
|
664
|
+
@available_voice_regions = {}
|
665
|
+
|
666
|
+
data = JSON.parse API::Server.regions(@bot.token, @id)
|
667
|
+
@available_voice_regions = data.map { |e| VoiceRegion.new e }
|
668
|
+
end
|
669
|
+
|
670
|
+
# @return [VoiceRegion, nil] voice region data for this server's region
|
671
|
+
# @note This may return `nil` if this server's voice region is deprecated.
|
672
|
+
def region
|
673
|
+
available_voice_regions.find { |e| e.id == @region_id }
|
674
|
+
end
|
675
|
+
|
676
|
+
# Moves the server to another region. This will cause a voice interruption of at most a second.
|
677
|
+
# @param region [String] The new region the server should be in.
|
678
|
+
def region=(region)
|
679
|
+
update_server_data(region: region.to_s)
|
680
|
+
end
|
681
|
+
|
682
|
+
# Sets the server's icon.
|
683
|
+
# @param icon [String, #read] The new icon, in base64-encoded JPG format.
|
684
|
+
def icon=(icon)
|
685
|
+
if icon.respond_to? :read
|
686
|
+
icon_string = 'data:image/jpg;base64,'
|
687
|
+
icon_string += Base64.strict_encode64(icon.read)
|
688
|
+
update_server_data(icon_id: icon_string)
|
689
|
+
else
|
690
|
+
update_server_data(icon_id: icon)
|
691
|
+
end
|
692
|
+
end
|
693
|
+
|
694
|
+
# Sets the server's AFK channel.
|
695
|
+
# @param afk_channel [Channel, nil] The new AFK channel, or `nil` if there should be none set.
|
696
|
+
def afk_channel=(afk_channel)
|
697
|
+
update_server_data(afk_channel_id: afk_channel.resolve_id)
|
698
|
+
end
|
699
|
+
|
700
|
+
# Sets the server's system channel.
|
701
|
+
# @param system_channel [Channel, String, Integer, nil] The new system channel, or `nil` should it be disabled.
|
702
|
+
def system_channel=(system_channel)
|
703
|
+
update_server_data(system_channel_id: system_channel.resolve_id)
|
704
|
+
end
|
705
|
+
|
706
|
+
# Sets the amount of time after which a user gets moved into the AFK channel.
|
707
|
+
# @param afk_timeout [Integer] The AFK timeout, in seconds.
|
708
|
+
def afk_timeout=(afk_timeout)
|
709
|
+
update_server_data(afk_timeout: afk_timeout)
|
710
|
+
end
|
711
|
+
|
712
|
+
# A map of possible server verification levels to symbol names
|
713
|
+
VERIFICATION_LEVELS = {
|
714
|
+
none: 0,
|
715
|
+
low: 1,
|
716
|
+
medium: 2,
|
717
|
+
high: 3,
|
718
|
+
very_high: 4
|
719
|
+
}.freeze
|
720
|
+
|
721
|
+
# @return [Symbol] the verification level of the server (:none = none, :low = 'Must have a verified email on their Discord account', :medium = 'Has to be registered with Discord for at least 5 minutes', :high = 'Has to be a member of this server for at least 10 minutes', :very_high = 'Must have a verified phone on their Discord account').
|
722
|
+
def verification_level
|
723
|
+
VERIFICATION_LEVELS.key @verification_level
|
724
|
+
end
|
725
|
+
|
726
|
+
# Sets the verification level of the server
|
727
|
+
# @param level [Integer, Symbol] The verification level from 0-4 or Symbol (see {VERIFICATION_LEVELS})
|
728
|
+
def verification_level=(level)
|
729
|
+
level = VERIFICATION_LEVELS[level] if level.is_a?(Symbol)
|
730
|
+
|
731
|
+
update_server_data(verification_level: level)
|
732
|
+
end
|
733
|
+
|
734
|
+
# A map of possible message notification levels to symbol names
|
735
|
+
NOTIFICATION_LEVELS = {
|
736
|
+
all_messages: 0,
|
737
|
+
only_mentions: 1
|
738
|
+
}.freeze
|
739
|
+
|
740
|
+
# @return [Symbol] the default message notifications settings of the server (:all = 'All messages', :mentions = 'Only @mentions').
|
741
|
+
def default_message_notifications
|
742
|
+
NOTIFICATION_LEVELS.key @default_message_notifications
|
743
|
+
end
|
744
|
+
|
745
|
+
# Sets the default message notification level
|
746
|
+
# @param notification_level [Integer, Symbol] The default message notification 0-1 or Symbol (see {NOTIFICATION_LEVELS})
|
747
|
+
def default_message_notifications=(notification_level)
|
748
|
+
notification_level = NOTIFICATION_LEVELS[notification_level] if notification_level.is_a?(Symbol)
|
749
|
+
|
750
|
+
update_server_data(default_message_notifications: notification_level)
|
751
|
+
end
|
752
|
+
|
753
|
+
alias_method :notification_level=, :default_message_notifications=
|
754
|
+
|
755
|
+
# Sets the server splash
|
756
|
+
# @param splash_hash [String] The splash hash
|
757
|
+
def splash=(splash_hash)
|
758
|
+
update_server_data(splash: splash_hash)
|
759
|
+
end
|
760
|
+
|
761
|
+
# A map of possible content filter levels to symbol names
|
762
|
+
FILTER_LEVELS = {
|
763
|
+
disabled: 0,
|
764
|
+
members_without_roles: 1,
|
765
|
+
all_members: 2
|
766
|
+
}.freeze
|
767
|
+
|
768
|
+
# @return [Symbol] the explicit content filter level of the server (:none = 'Don't scan any messages.', :exclude_roles = 'Scan messages for members without a role.', :all = 'Scan messages sent by all members.').
|
769
|
+
def explicit_content_filter
|
770
|
+
FILTER_LEVELS.key @explicit_content_filter
|
771
|
+
end
|
772
|
+
|
773
|
+
alias_method :content_filter_level, :explicit_content_filter
|
774
|
+
|
775
|
+
# Sets the server content filter.
|
776
|
+
# @param filter_level [Integer, Symbol] The content filter from 0-2 or Symbol (see {FILTER_LEVELS})
|
777
|
+
def explicit_content_filter=(filter_level)
|
778
|
+
filter_level = FILTER_LEVELS[filter_level] if filter_level.is_a?(Symbol)
|
779
|
+
|
780
|
+
update_server_data(explicit_content_filter: filter_level)
|
781
|
+
end
|
782
|
+
|
783
|
+
# @return [true, false] whether this server has any emoji or not.
|
784
|
+
def any_emoji?
|
785
|
+
@emoji.any?
|
786
|
+
end
|
787
|
+
|
788
|
+
alias_method :has_emoji?, :any_emoji?
|
789
|
+
alias_method :emoji?, :any_emoji?
|
790
|
+
|
791
|
+
# Requests a list of Webhooks on the server.
|
792
|
+
# @return [Array<Webhook>] webhooks on the server.
|
793
|
+
def webhooks
|
794
|
+
webhooks = JSON.parse(API::Server.webhooks(@bot.token, @id))
|
795
|
+
webhooks.map { |webhook| Webhook.new(webhook, @bot) }
|
796
|
+
end
|
797
|
+
|
798
|
+
# Requests a list of Invites to the server.
|
799
|
+
# @return [Array<Invite>] invites to the server.
|
800
|
+
def invites
|
801
|
+
invites = JSON.parse(API::Server.invites(@bot.token, @id))
|
802
|
+
invites.map { |invite| Invite.new(invite, @bot) }
|
803
|
+
end
|
804
|
+
|
805
|
+
# Processes a GUILD_MEMBERS_CHUNK packet, specifically the members field
|
806
|
+
# @note For internal use only
|
807
|
+
# @!visibility private
|
808
|
+
def process_chunk(members)
|
809
|
+
process_members(members)
|
810
|
+
@processed_chunk_members += members.length
|
811
|
+
LOGGER.debug("Processed one chunk on server #{@id} - length #{members.length}")
|
812
|
+
|
813
|
+
# Don't bother with the rest of the method if it's not truly the last packet
|
814
|
+
return unless @processed_chunk_members == @member_count
|
815
|
+
|
816
|
+
LOGGER.debug("Finished chunking server #{@id}")
|
817
|
+
|
818
|
+
# Reset everything to normal
|
819
|
+
@chunked = true
|
820
|
+
@processed_chunk_members = 0
|
821
|
+
end
|
822
|
+
|
823
|
+
# @return [Channel, nil] the AFK voice channel of this server, or `nil` if none is set.
|
824
|
+
def afk_channel
|
825
|
+
@bot.channel(@afk_channel_id) if @afk_channel_id
|
826
|
+
end
|
827
|
+
|
828
|
+
# @return [Channel, nil] the system channel (used for automatic welcome messages) of a server, or `nil` if none is set.
|
829
|
+
def system_channel
|
830
|
+
@bot.channel(@system_channel_id) if @system_channel_id
|
831
|
+
end
|
832
|
+
|
833
|
+
# Updates the cached data with new data
|
834
|
+
# @note For internal use only
|
835
|
+
# @!visibility private
|
836
|
+
def update_data(new_data = nil)
|
837
|
+
new_data ||= JSON.parse(API::Server.resolve(@bot.token, @id))
|
838
|
+
@name = new_data[:name] || new_data['name'] || @name
|
839
|
+
@region_id = new_data[:region] || new_data['region'] || @region_id
|
840
|
+
@icon_id = new_data[:icon] || new_data['icon'] || @icon_id
|
841
|
+
@afk_timeout = new_data[:afk_timeout] || new_data['afk_timeout'] || @afk_timeout
|
842
|
+
|
843
|
+
afk_channel_id = new_data[:afk_channel_id] || new_data['afk_channel_id'] || @afk_channel
|
844
|
+
@afk_channel_id = afk_channel_id.nil? ? nil : afk_channel_id.resolve_id
|
845
|
+
embed_channel_id = new_data[:embed_channel_id] || new_data['embed_channel_id'] || @embed_channel
|
846
|
+
@embed_channel_id = embed_channel_id.nil? ? nil : embed_channel_id.resolve_id
|
847
|
+
system_channel_id = new_data[:system_channel_id] || new_data['system_channel_id'] || @system_channel
|
848
|
+
@system_channel_id = system_channel_id.nil? ? nil : system_channel_id.resolve_id
|
849
|
+
|
850
|
+
@embed_enabled = new_data[:embed_enabled] || new_data['embed_enabled']
|
851
|
+
@splash = new_data[:splash_id] || new_data['splash_id'] || @splash_id
|
852
|
+
|
853
|
+
@verification_level = new_data[:verification_level] || new_data['verification_level'] || @verification_level
|
854
|
+
@explicit_content_filter = new_data[:explicit_content_filter] || new_data['explicit_content_filter'] || @explicit_content_filter
|
855
|
+
@default_message_notifications = new_data[:default_message_notifications] || new_data['default_message_notifications'] || @default_message_notifications
|
856
|
+
end
|
857
|
+
|
858
|
+
# Adds a channel to this server's cache
|
859
|
+
# @note For internal use only
|
860
|
+
# @!visibility private
|
861
|
+
def add_channel(channel)
|
862
|
+
@channels << channel
|
863
|
+
@channels_by_id[channel.id] = channel
|
864
|
+
end
|
865
|
+
|
866
|
+
# Deletes a channel from this server's cache
|
867
|
+
# @note For internal use only
|
868
|
+
# @!visibility private
|
869
|
+
def delete_channel(id)
|
870
|
+
@channels.reject! { |e| e.id == id }
|
871
|
+
@channels_by_id.delete(id)
|
872
|
+
end
|
873
|
+
|
874
|
+
# Updates the cached emoji data with new data
|
875
|
+
# @note For internal use only
|
876
|
+
# @!visibility private
|
877
|
+
def update_emoji_data(new_data)
|
878
|
+
@emoji = {}
|
879
|
+
process_emoji(new_data['emojis'])
|
880
|
+
end
|
881
|
+
|
882
|
+
# The inspect method is overwritten to give more useful output
|
883
|
+
def inspect
|
884
|
+
"<Server name=#{@name} id=#{@id} large=#{@large} region=#{@region} owner=#{@owner} afk_channel_id=#{@afk_channel_id} system_channel_id=#{@system_channel_id} afk_timeout=#{@afk_timeout}>"
|
885
|
+
end
|
886
|
+
|
887
|
+
private
|
888
|
+
|
889
|
+
def update_server_data(new_data)
|
890
|
+
response = JSON.parse(API::Server.update(@bot.token, @id,
|
891
|
+
new_data[:name] || @name,
|
892
|
+
new_data[:region] || @region_id,
|
893
|
+
new_data[:icon_id] || @icon_id,
|
894
|
+
new_data[:afk_channel_id] || @afk_channel_id,
|
895
|
+
new_data[:afk_timeout] || @afk_timeout,
|
896
|
+
new_data[:splash] || @splash,
|
897
|
+
new_data[:default_message_notifications] || @default_message_notifications,
|
898
|
+
new_data[:verification_level] || @verification_level,
|
899
|
+
new_data[:explicit_content_filter] || @explicit_content_filter,
|
900
|
+
new_data[:system_channel_id] || @system_channel_id))
|
901
|
+
update_data(response)
|
902
|
+
end
|
903
|
+
|
904
|
+
def process_roles(roles)
|
905
|
+
# Create roles
|
906
|
+
@roles = []
|
907
|
+
@roles_by_id = {}
|
908
|
+
|
909
|
+
return unless roles
|
910
|
+
|
911
|
+
roles.each do |element|
|
912
|
+
role = Role.new(element, @bot, self)
|
913
|
+
@roles << role
|
914
|
+
@roles_by_id[role.id] = role
|
915
|
+
end
|
916
|
+
end
|
917
|
+
|
918
|
+
def process_emoji(emoji)
|
919
|
+
return if emoji.empty?
|
920
|
+
|
921
|
+
emoji.each do |element|
|
922
|
+
new_emoji = Emoji.new(element, @bot, self)
|
923
|
+
@emoji[new_emoji.id] = new_emoji
|
924
|
+
end
|
925
|
+
end
|
926
|
+
|
927
|
+
def process_members(members)
|
928
|
+
return unless members
|
929
|
+
|
930
|
+
members.each do |element|
|
931
|
+
member = Member.new(element, self, @bot)
|
932
|
+
@members[member.id] = member
|
933
|
+
end
|
934
|
+
end
|
935
|
+
|
936
|
+
def process_presences(presences)
|
937
|
+
# Update user statuses with presence info
|
938
|
+
return unless presences
|
939
|
+
|
940
|
+
presences.each do |element|
|
941
|
+
next unless element['user']
|
942
|
+
|
943
|
+
user_id = element['user']['id'].to_i
|
944
|
+
user = @members[user_id]
|
945
|
+
if user
|
946
|
+
user.update_presence(element)
|
947
|
+
else
|
948
|
+
LOGGER.warn "Rogue presence update! #{element['user']['id']} on #{@id}"
|
949
|
+
end
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
953
|
+
def process_channels(channels)
|
954
|
+
@channels = []
|
955
|
+
@channels_by_id = {}
|
956
|
+
|
957
|
+
return unless channels
|
958
|
+
|
959
|
+
channels.each do |element|
|
960
|
+
channel = @bot.ensure_channel(element, self)
|
961
|
+
@channels << channel
|
962
|
+
@channels_by_id[channel.id] = channel
|
963
|
+
end
|
964
|
+
end
|
965
|
+
|
966
|
+
def process_voice_states(voice_states)
|
967
|
+
return unless voice_states
|
968
|
+
|
969
|
+
voice_states.each do |element|
|
970
|
+
update_voice_state(element)
|
971
|
+
end
|
972
|
+
end
|
973
|
+
end
|
974
|
+
|
975
|
+
# A ban entry on a server
|
976
|
+
class ServerBan
|
977
|
+
# @return [String, nil] the reason the user was banned, if provided
|
978
|
+
attr_reader :reason
|
979
|
+
|
980
|
+
# @return [User] the user that was banned
|
981
|
+
attr_reader :user
|
982
|
+
|
983
|
+
# @return [Server] the server this ban belongs to
|
984
|
+
attr_reader :server
|
985
|
+
|
986
|
+
# @!visibility private
|
987
|
+
def initialize(server, user, reason)
|
988
|
+
@server = server
|
989
|
+
@user = user
|
990
|
+
@reason = reason
|
991
|
+
end
|
992
|
+
|
993
|
+
# Removes this ban on the associated user in the server
|
994
|
+
# @param reason [String] the reason for removing the ban
|
995
|
+
def remove(reason = nil)
|
996
|
+
@server.unban(user, reason)
|
997
|
+
end
|
998
|
+
|
999
|
+
alias_method :unban, :remove
|
1000
|
+
alias_method :lift, :remove
|
1001
|
+
end
|
1002
|
+
end
|