discordrb 1.3.12 → 1.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 +4 -4
- data/Rakefile +4 -0
- data/bin/console +3 -3
- data/discordrb.gemspec +14 -14
- data/examples/commands.rb +8 -8
- data/examples/ping.rb +3 -3
- data/examples/pm_send.rb +2 -2
- data/lib/discordrb.rb +1 -0
- data/lib/discordrb/api.rb +34 -8
- data/lib/discordrb/bot.rb +126 -18
- data/lib/discordrb/commands/command_bot.rb +19 -5
- data/lib/discordrb/data.rb +272 -39
- data/lib/discordrb/events/generic.rb +5 -1
- data/lib/discordrb/events/guilds.rb +56 -0
- data/lib/discordrb/games.rb +6 -4
- data/lib/discordrb/games_list.rb +1 -306
- data/lib/discordrb/permissions.rb +29 -3
- data/lib/discordrb/version.rb +1 -1
- data/util/update_lists.rb +20 -2
- metadata +3 -2
@@ -88,7 +88,7 @@ module Discordrb::Commands
|
|
88
88
|
debug("Executing command #{name} with arguments #{arguments}")
|
89
89
|
command = @commands[name]
|
90
90
|
unless command
|
91
|
-
event.respond @attributes[:command_doesnt_exist_message].gsub('%command%', name) if @attributes[:command_doesnt_exist_message]
|
91
|
+
event.respond @attributes[:command_doesnt_exist_message].gsub('%command%', name.to_s) if @attributes[:command_doesnt_exist_message]
|
92
92
|
return
|
93
93
|
end
|
94
94
|
if permission?(user(event.user.id), command.attributes[:permission_level], event.server)
|
@@ -118,10 +118,24 @@ module Discordrb::Commands
|
|
118
118
|
return
|
119
119
|
end
|
120
120
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
121
|
+
execute_chain(chain, event)
|
122
|
+
end
|
123
|
+
|
124
|
+
def execute_chain(chain, event)
|
125
|
+
t = Thread.new do
|
126
|
+
@event_threads << t
|
127
|
+
Thread.current[:discordrb_name] = "ct-#{@current_thread += 1}"
|
128
|
+
begin
|
129
|
+
debug("Parsing command chain #{chain}")
|
130
|
+
result = (@attributes[:advanced_functionality]) ? CommandChain.new(chain, self).execute(event) : simple_execute(chain, event)
|
131
|
+
result = event.saved_message + (result || '')
|
132
|
+
event.respond result if result
|
133
|
+
rescue => e
|
134
|
+
log_exception(e)
|
135
|
+
ensure
|
136
|
+
@event_threads.delete(t)
|
137
|
+
end
|
138
|
+
end
|
125
139
|
end
|
126
140
|
|
127
141
|
def set_user_permission(id, level)
|
data/lib/discordrb/data.rb
CHANGED
@@ -4,7 +4,9 @@ require 'ostruct'
|
|
4
4
|
require 'discordrb/permissions'
|
5
5
|
require 'discordrb/api'
|
6
6
|
require 'discordrb/games'
|
7
|
+
require 'base64'
|
7
8
|
|
9
|
+
# Discordrb module
|
8
10
|
module Discordrb
|
9
11
|
# User on Discord, including internal data like discriminators
|
10
12
|
class User
|
@@ -121,25 +123,164 @@ module Discordrb
|
|
121
123
|
end
|
122
124
|
end
|
123
125
|
|
126
|
+
# A class that represents the bot user itself and has methods to change stuff
|
127
|
+
class Profile < User
|
128
|
+
def initialize(data, bot, email, password)
|
129
|
+
super(data, bot)
|
130
|
+
@email = email
|
131
|
+
@password = password
|
132
|
+
end
|
133
|
+
|
134
|
+
def bot?
|
135
|
+
true
|
136
|
+
end
|
137
|
+
|
138
|
+
def username=(username)
|
139
|
+
update_server_data(username: username)
|
140
|
+
end
|
141
|
+
|
142
|
+
def email=(email)
|
143
|
+
update_server_data(email: email)
|
144
|
+
end
|
145
|
+
|
146
|
+
def password=(password)
|
147
|
+
update_server_data(new_password: password)
|
148
|
+
end
|
149
|
+
|
150
|
+
def avatar=(avatar)
|
151
|
+
if avatar.is_a? File
|
152
|
+
avatar_string = 'data:image/jpg;base64,'
|
153
|
+
avatar_string += Base64.strict_encode64(avatar.read)
|
154
|
+
update_server_data(avatar: avatar_string)
|
155
|
+
else
|
156
|
+
update_server_data(avatar: avatar)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def update_data(new_data)
|
161
|
+
@email = new_data[:email] || @email
|
162
|
+
@password = new_data[:new_password] || @password
|
163
|
+
@username = new_data[:username] || @username
|
164
|
+
@avatar = new_data[:avatar] || @avatar
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
def update_server_data(new_data)
|
170
|
+
API.update_user(@bot.token,
|
171
|
+
new_data[:email] || @email,
|
172
|
+
@password,
|
173
|
+
new_data[:username] || @username,
|
174
|
+
new_data[:avatar] || @avatar,
|
175
|
+
new_data[:new_password] || nil)
|
176
|
+
update_data(new_data)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
124
180
|
# A Discord role that contains permissions and applies to certain users
|
125
181
|
class Role
|
126
|
-
attr_reader :permissions, :name, :id, :hoist, :
|
182
|
+
attr_reader :permissions, :name, :id, :hoist, :colour
|
183
|
+
alias_method :color, :colour
|
184
|
+
|
185
|
+
# Class that writes data for a Permissions object
|
186
|
+
class RoleWriter
|
187
|
+
def initialize(role, token)
|
188
|
+
@role = role
|
189
|
+
@token = token
|
190
|
+
end
|
191
|
+
|
192
|
+
def write(bits)
|
193
|
+
@role.send(:packed=, bits, false)
|
194
|
+
end
|
195
|
+
end
|
127
196
|
|
128
197
|
def initialize(data, bot, server = nil)
|
129
198
|
@bot = bot
|
130
199
|
@server = server
|
131
|
-
@permissions = Permissions.new(data['permissions'])
|
200
|
+
@permissions = Permissions.new(data['permissions'], RoleWriter.new(self, @bot.token))
|
132
201
|
@name = data['name']
|
133
202
|
@id = data['id'].to_i
|
134
203
|
@hoist = data['hoist']
|
135
|
-
@
|
204
|
+
@colour = ColourRGB.new(data['color'])
|
136
205
|
end
|
137
206
|
|
138
207
|
def update_from(other)
|
139
208
|
@permissions = other.permissions
|
140
209
|
@name = other.name
|
141
210
|
@hoist = other.hoist
|
142
|
-
@
|
211
|
+
@colour = other.colour
|
212
|
+
end
|
213
|
+
|
214
|
+
def update_data(new_data)
|
215
|
+
@name = new_data[:name] || new_data['name'] || @name
|
216
|
+
@hoist = new_data['hoist'] unless new_data['hoist'].nil?
|
217
|
+
@hoist = new_data[:hoist] unless new_data[:hoist].nil?
|
218
|
+
@colour = new_data[:colour] || (new_data['color'] ? ColourRGB.new(new_data['color']) : @colour)
|
219
|
+
end
|
220
|
+
|
221
|
+
def name=(name)
|
222
|
+
update_role_data(name: name)
|
223
|
+
end
|
224
|
+
|
225
|
+
def hoist=(hoist)
|
226
|
+
update_role_data(hoist: hoist)
|
227
|
+
end
|
228
|
+
|
229
|
+
def colour=(colour)
|
230
|
+
update_role_data(colour: colour)
|
231
|
+
end
|
232
|
+
|
233
|
+
alias_method :color=, :colour=
|
234
|
+
|
235
|
+
def packed=(packed, update_perms = true)
|
236
|
+
update_role_data(permissions: packed)
|
237
|
+
@permissions.bits = packed if update_perms
|
238
|
+
end
|
239
|
+
|
240
|
+
def delete
|
241
|
+
API.delete_role(@bot.token, @server.id, @id)
|
242
|
+
@server.delete_role(@id)
|
243
|
+
end
|
244
|
+
|
245
|
+
private
|
246
|
+
|
247
|
+
def update_role_data(new_data)
|
248
|
+
API.update_role(@bot.token, @server.id, @id,
|
249
|
+
new_data[:name] || @name,
|
250
|
+
(new_data[:colour] || @colour).combined,
|
251
|
+
!(!(new_data[:hoist].nil? ? new_data[:hoist] : @hoist)),
|
252
|
+
new_data[:permissions] || @permissions.bits)
|
253
|
+
update_data(new_data)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# A Discord invite to a channel
|
258
|
+
class Invite
|
259
|
+
attr_reader :channel, :uses, :inviter, :temporary, :revoked, :xkcd, :code
|
260
|
+
alias_method :max_uses, :uses
|
261
|
+
alias_method :user, :inviter
|
262
|
+
|
263
|
+
alias_method :temporary?, :temporary
|
264
|
+
alias_method :revoked?, :revoked
|
265
|
+
alias_method :xkcd?, :xkcd
|
266
|
+
|
267
|
+
delegate :server, to: :channel
|
268
|
+
|
269
|
+
def initialize(data, bot)
|
270
|
+
@bot = bot
|
271
|
+
|
272
|
+
@channel = Channel.new(data['channel'], bot)
|
273
|
+
@uses = data['uses']
|
274
|
+
@inviter = @bot.user(data['inviter']['id'].to_i) || User.new(data['inviter'], bot)
|
275
|
+
@temporary = data['temporary']
|
276
|
+
@revoked = data['revoked']
|
277
|
+
@xkcd = data['xkcdpass']
|
278
|
+
|
279
|
+
@code = data['code']
|
280
|
+
end
|
281
|
+
|
282
|
+
def delete
|
283
|
+
API.delete_invite(@bot.token, @code)
|
143
284
|
end
|
144
285
|
end
|
145
286
|
|
@@ -231,6 +372,11 @@ module Discordrb
|
|
231
372
|
end
|
232
373
|
end
|
233
374
|
|
375
|
+
def history(amount, before_id = nil, after_id = nil)
|
376
|
+
logs = API.channel_log(@bot.token, @id, amount, before_id, after_id)
|
377
|
+
JSON.parse(logs).map { |message| Message.new(message, @bot) }
|
378
|
+
end
|
379
|
+
|
234
380
|
def update_overwrites(overwrites)
|
235
381
|
@permission_overwrites = overwrites
|
236
382
|
end
|
@@ -240,8 +386,21 @@ module Discordrb
|
|
240
386
|
@bot.add_await(key, MessageEvent, { in: @id }.merge(attributes), &block)
|
241
387
|
end
|
242
388
|
|
389
|
+
def make_invite(max_age = 0, max_uses = 0, temporary = false, xkcd = false)
|
390
|
+
response = API.create_invite(@bot.token, @id, max_age, max_uses, temporary, xkcd)
|
391
|
+
Invite.new(JSON.parse(response), @bot)
|
392
|
+
end
|
393
|
+
|
394
|
+
# Starts typing, which displays the typing indicator on the client for five seconds.
|
395
|
+
# If you want to keep typing you'll have to resend this every five seconds. (An abstraction
|
396
|
+
# for this will eventually be coming)
|
397
|
+
def start_typing
|
398
|
+
API.start_typing(@bot.token, @id)
|
399
|
+
end
|
400
|
+
|
243
401
|
alias_method :send, :send_message
|
244
402
|
alias_method :message, :send_message
|
403
|
+
alias_method :invite, :make_invite
|
245
404
|
|
246
405
|
private
|
247
406
|
|
@@ -295,74 +454,88 @@ module Discordrb
|
|
295
454
|
|
296
455
|
# A server on Discord
|
297
456
|
class Server
|
298
|
-
attr_reader :region, :name, :owner_id, :id, :members, :channels, :roles
|
457
|
+
attr_reader :region, :name, :owner_id, :id, :members, :channels, :roles, :icon, :afk_timeout, :afk_channel_id
|
299
458
|
|
300
459
|
def initialize(data, bot)
|
301
460
|
@bot = bot
|
302
|
-
@region = data['region']
|
303
|
-
@name = data['name']
|
304
461
|
@owner_id = data['owner_id'].to_i
|
305
462
|
@id = data['id'].to_i
|
463
|
+
update_data(data)
|
464
|
+
|
465
|
+
process_roles(data['roles'])
|
466
|
+
process_members(data['members'])
|
467
|
+
process_presences(data['presences'])
|
468
|
+
process_channels(data['channels'])
|
469
|
+
process_voice_states(data['voice_states'])
|
470
|
+
end
|
306
471
|
|
472
|
+
def process_roles(roles)
|
307
473
|
# Create roles
|
308
474
|
@roles = []
|
309
|
-
roles_by_id = {}
|
310
|
-
|
311
|
-
role = Role.new(element, bot)
|
475
|
+
@roles_by_id = {}
|
476
|
+
roles.each do |element|
|
477
|
+
role = Role.new(element, @bot, self)
|
312
478
|
@roles << role
|
313
|
-
roles_by_id[role.id] = role
|
479
|
+
@roles_by_id[role.id] = role
|
314
480
|
end
|
481
|
+
end
|
315
482
|
|
483
|
+
def process_members(members)
|
316
484
|
@members = []
|
317
|
-
members_by_id = {}
|
485
|
+
@members_by_id = {}
|
318
486
|
|
319
|
-
|
320
|
-
|
487
|
+
return unless members
|
488
|
+
members.each do |element|
|
489
|
+
user = User.new(element['user'], @bot)
|
321
490
|
@members << user
|
322
|
-
members_by_id[user.id] = user
|
491
|
+
@members_by_id[user.id] = user
|
323
492
|
user_roles = []
|
324
493
|
element['roles'].each do |e|
|
325
494
|
role_id = e.to_i
|
326
|
-
user_roles << roles_by_id[role_id]
|
495
|
+
user_roles << @roles_by_id[role_id]
|
327
496
|
end
|
328
497
|
user.update_roles(self, user_roles)
|
329
498
|
end
|
499
|
+
end
|
330
500
|
|
501
|
+
def process_presences(presences)
|
331
502
|
# Update user statuses with presence info
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
end
|
503
|
+
return unless presences
|
504
|
+
presences.each do |element|
|
505
|
+
next unless element['user']
|
506
|
+
user_id = element['user']['id'].to_i
|
507
|
+
user = @members_by_id[user_id]
|
508
|
+
if user
|
509
|
+
user.status = element['status'].to_sym
|
510
|
+
user.game = Discordrb::Games.find_game(element['game_id'])
|
341
511
|
end
|
342
512
|
end
|
513
|
+
end
|
343
514
|
|
515
|
+
def process_channels(channels)
|
344
516
|
@channels = []
|
345
|
-
channels_by_id = {}
|
517
|
+
@channels_by_id = {}
|
346
518
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
end
|
519
|
+
return unless channels
|
520
|
+
channels.each do |element|
|
521
|
+
channel = Channel.new(element, @bot, self)
|
522
|
+
@channels << channel
|
523
|
+
@channels_by_id[channel.id] = channel
|
353
524
|
end
|
525
|
+
end
|
354
526
|
|
355
|
-
|
356
|
-
|
527
|
+
def process_voice_states(voice_states)
|
528
|
+
return unless voice_states
|
529
|
+
voice_states.each do |element|
|
357
530
|
user_id = element['user_id'].to_i
|
358
|
-
user = members_by_id[user_id]
|
531
|
+
user = @members_by_id[user_id]
|
359
532
|
next unless user
|
360
533
|
user.server_mute = element['mute']
|
361
534
|
user.server_deaf = element['deaf']
|
362
535
|
user.self_mute = element['self_mute']
|
363
536
|
user.self_mute = element['self_mute']
|
364
537
|
channel_id = element['channel_id']
|
365
|
-
channel = channel_id ? channels_by_id[channel_id] : nil
|
538
|
+
channel = channel_id ? @channels_by_id[channel_id] : nil
|
366
539
|
user.move(channel)
|
367
540
|
end
|
368
541
|
end
|
@@ -374,7 +547,7 @@ module Discordrb
|
|
374
547
|
def delete_role(role_id)
|
375
548
|
@roles.reject! { |r| r.id == role_id }
|
376
549
|
@members.each do |user|
|
377
|
-
new_roles = user.roles.reject { |r| r.id == role_id }
|
550
|
+
new_roles = user.roles[@id].reject { |r| r.id == role_id }
|
378
551
|
user.update_roles(self, new_roles)
|
379
552
|
end
|
380
553
|
@channels.each do |channel|
|
@@ -396,6 +569,13 @@ module Discordrb
|
|
396
569
|
Channel.new(JSON.parse(response), @bot)
|
397
570
|
end
|
398
571
|
|
572
|
+
def create_role
|
573
|
+
response = API.create_role(@bot.token, @id)
|
574
|
+
role = Role.new(JSON.parse(response), @bot)
|
575
|
+
@roles << role
|
576
|
+
role
|
577
|
+
end
|
578
|
+
|
399
579
|
def ban(user, message_days = 0)
|
400
580
|
API.ban_user(@bot.token, @id, user.id, message_days)
|
401
581
|
end
|
@@ -407,16 +587,69 @@ module Discordrb
|
|
407
587
|
def kick(user)
|
408
588
|
API.kick_user(@bot.token, @id, user.id)
|
409
589
|
end
|
590
|
+
|
591
|
+
def delete
|
592
|
+
API.delete_server(@bot.token, @id)
|
593
|
+
end
|
594
|
+
|
595
|
+
def name=(name)
|
596
|
+
update_server_data(name: name)
|
597
|
+
end
|
598
|
+
|
599
|
+
def region=(region)
|
600
|
+
update_server_data(region: region.to_s)
|
601
|
+
end
|
602
|
+
|
603
|
+
def icon=(icon)
|
604
|
+
update_server_data(icon: icon)
|
605
|
+
end
|
606
|
+
|
607
|
+
def afk_channel=(afk_channel)
|
608
|
+
update_server_data(afk_channel_id: afk_channel.id)
|
609
|
+
end
|
610
|
+
|
611
|
+
def afk_channel_id=(afk_channel_id)
|
612
|
+
update_server_data(afk_channel_id: afk_channel_id)
|
613
|
+
end
|
614
|
+
|
615
|
+
def afk_timeout=(afk_timeout)
|
616
|
+
update_server_data(afk_timeout: afk_timeout)
|
617
|
+
end
|
618
|
+
|
619
|
+
def update_data(new_data)
|
620
|
+
@name = new_data[:name] || new_data['name'] || @name
|
621
|
+
@region = new_data[:region] || new_data['region'] || @region
|
622
|
+
@icon = new_data[:icon] || new_data['icon'] || @icon
|
623
|
+
@afk_timeout = new_data[:afk_timeout] || new_data['afk_timeout'].to_i || @afk_timeout
|
624
|
+
|
625
|
+
afk_channel_id = new_data[:afk_channel_id] || new_data['afk_channel_id'].to_i || @afk_channel.id
|
626
|
+
@afk_channel = @bot.channel(afk_channel_id) if afk_channel_id != 0 && (!@afk_channel || afk_channel_id != @afk_channel.id)
|
627
|
+
end
|
628
|
+
|
629
|
+
private
|
630
|
+
|
631
|
+
def update_server_data(new_data)
|
632
|
+
API.update_server(@bot.token, @id,
|
633
|
+
new_data[:name] || @name,
|
634
|
+
new_data[:region] || @region,
|
635
|
+
new_data[:icon] || @icon,
|
636
|
+
new_data[:afk_channel_id] || @afk_channel_id,
|
637
|
+
new_data[:afk_timeout] || @afk_timeout)
|
638
|
+
update_data(new_data)
|
639
|
+
end
|
410
640
|
end
|
411
641
|
|
412
642
|
# A colour (red, green and blue values). Used for role colours
|
413
|
-
class
|
414
|
-
attr_reader :red, :green, :blue
|
643
|
+
class ColourRGB
|
644
|
+
attr_reader :red, :green, :blue, :combined
|
415
645
|
|
416
646
|
def initialize(combined)
|
647
|
+
@combined = combined
|
417
648
|
@red = (combined >> 16) & 0xFF
|
418
649
|
@green = (combined >> 8) & 0xFF
|
419
650
|
@blue = combined & 0xFF
|
420
651
|
end
|
421
652
|
end
|
653
|
+
|
654
|
+
ColorRGB = ColourRGB
|
422
655
|
end
|