discorb 0.19.0 → 0.20.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.
- checksums.yaml +4 -4
- data/.github/workflows/build_version.yml +2 -2
- data/.rubocop.yml +12 -75
- data/Changelog.md +10 -0
- data/Rakefile +482 -454
- data/lib/discorb/allowed_mentions.rb +68 -72
- data/lib/discorb/app_command/command.rb +466 -398
- data/lib/discorb/app_command/common.rb +65 -25
- data/lib/discorb/app_command/handler.rb +304 -266
- data/lib/discorb/app_command.rb +5 -5
- data/lib/discorb/application.rb +198 -197
- data/lib/discorb/asset.rb +101 -101
- data/lib/discorb/attachment.rb +134 -119
- data/lib/discorb/audit_logs.rb +412 -385
- data/lib/discorb/automod.rb +279 -269
- data/lib/discorb/channel/base.rb +107 -108
- data/lib/discorb/channel/category.rb +32 -32
- data/lib/discorb/channel/container.rb +44 -44
- data/lib/discorb/channel/dm.rb +26 -28
- data/lib/discorb/channel/guild.rb +311 -246
- data/lib/discorb/channel/stage.rb +156 -140
- data/lib/discorb/channel/text.rb +430 -336
- data/lib/discorb/channel/thread.rb +374 -325
- data/lib/discorb/channel/voice.rb +85 -79
- data/lib/discorb/channel.rb +5 -5
- data/lib/discorb/client.rb +635 -621
- data/lib/discorb/color.rb +178 -182
- data/lib/discorb/common.rb +168 -164
- data/lib/discorb/components/button.rb +107 -106
- data/lib/discorb/components/select_menu.rb +157 -145
- data/lib/discorb/components/text_input.rb +103 -106
- data/lib/discorb/components.rb +68 -66
- data/lib/discorb/dictionary.rb +135 -135
- data/lib/discorb/embed.rb +404 -398
- data/lib/discorb/emoji.rb +309 -302
- data/lib/discorb/emoji_table.rb +16099 -8857
- data/lib/discorb/error.rb +131 -131
- data/lib/discorb/event.rb +360 -314
- data/lib/discorb/event_handler.rb +39 -39
- data/lib/discorb/exe/about.rb +17 -17
- data/lib/discorb/exe/irb.rb +72 -67
- data/lib/discorb/exe/new.rb +323 -315
- data/lib/discorb/exe/run.rb +69 -68
- data/lib/discorb/exe/setup.rb +57 -55
- data/lib/discorb/exe/show.rb +12 -12
- data/lib/discorb/extend.rb +25 -45
- data/lib/discorb/extension.rb +89 -83
- data/lib/discorb/flag.rb +126 -128
- data/lib/discorb/gateway.rb +984 -804
- data/lib/discorb/gateway_events.rb +670 -638
- data/lib/discorb/gateway_requests.rb +45 -48
- data/lib/discorb/guild.rb +2115 -1626
- data/lib/discorb/guild_template.rb +280 -241
- data/lib/discorb/http.rb +247 -232
- data/lib/discorb/image.rb +42 -42
- data/lib/discorb/integration.rb +169 -161
- data/lib/discorb/intents.rb +161 -163
- data/lib/discorb/interaction/autocomplete.rb +76 -62
- data/lib/discorb/interaction/command.rb +279 -224
- data/lib/discorb/interaction/components.rb +114 -104
- data/lib/discorb/interaction/modal.rb +36 -32
- data/lib/discorb/interaction/response.rb +379 -336
- data/lib/discorb/interaction/root.rb +271 -257
- data/lib/discorb/interaction.rb +5 -5
- data/lib/discorb/invite.rb +154 -153
- data/lib/discorb/member.rb +344 -311
- data/lib/discorb/message.rb +615 -544
- data/lib/discorb/message_meta.rb +197 -186
- data/lib/discorb/modules.rb +371 -290
- data/lib/discorb/permission.rb +305 -291
- data/lib/discorb/presence.rb +352 -346
- data/lib/discorb/rate_limit.rb +81 -76
- data/lib/discorb/reaction.rb +55 -54
- data/lib/discorb/role.rb +272 -240
- data/lib/discorb/shard.rb +76 -74
- data/lib/discorb/sticker.rb +193 -171
- data/lib/discorb/user.rb +205 -188
- data/lib/discorb/utils/colored_puts.rb +16 -16
- data/lib/discorb/utils.rb +12 -16
- data/lib/discorb/voice_state.rb +305 -281
- data/lib/discorb/webhook.rb +537 -507
- data/lib/discorb.rb +62 -56
- data/sig/discorb/application.rbs +2 -0
- data/sig/discorb/automod.rbs +10 -1
- data/sig/discorb/guild.rbs +2 -0
- data/sig/discorb/message.rbs +2 -0
- data/sig/discorb/user.rbs +22 -20
- metadata +2 -2
data/lib/discorb/message.rb
CHANGED
@@ -1,544 +1,615 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Discorb
|
4
|
-
#
|
5
|
-
# Represents a message.
|
6
|
-
#
|
7
|
-
class Message < DiscordModel
|
8
|
-
# @return [Discorb::Snowflake] The ID of the message.
|
9
|
-
attr_reader :id
|
10
|
-
# @return [Discorb::User, Discorb::Member, Webhook::Message::Author] The user that sent the message.
|
11
|
-
attr_reader :author
|
12
|
-
# @return [String] The content of the message.
|
13
|
-
attr_reader :content
|
14
|
-
alias to_s content
|
15
|
-
# @return [Time] The time the message was created.
|
16
|
-
attr_reader :created_at
|
17
|
-
alias timestamp created_at
|
18
|
-
alias sent_at created_at
|
19
|
-
# @return [Time] The time the message was edited.
|
20
|
-
# @return [nil] If the message was not edited.
|
21
|
-
attr_reader :updated_at
|
22
|
-
alias edited_at updated_at
|
23
|
-
alias edited_timestamp updated_at
|
24
|
-
# @return [Array<Discorb::Attachment>] The attachments of the message.
|
25
|
-
attr_reader :attachments
|
26
|
-
# @return [Array<Discorb::Embed>] The embeds of the message.
|
27
|
-
attr_reader :embeds
|
28
|
-
# @return [Array<Discorb::Reaction>] The reactions of the message.
|
29
|
-
attr_reader :reactions
|
30
|
-
# @return [Discorb::Snowflake] The ID of the channel the message was sent in.
|
31
|
-
attr_reader :webhook_id
|
32
|
-
# @return [Symbol] The type of the message.
|
33
|
-
# Currently, this will be one of:
|
34
|
-
#
|
35
|
-
# * `:default`
|
36
|
-
# * `:recipient_add`
|
37
|
-
# * `:recipient_remove`
|
38
|
-
# * `:call`
|
39
|
-
# * `:channel_name_change`
|
40
|
-
# * `:channel_icon_change`
|
41
|
-
# * `:channel_pinned_message`
|
42
|
-
# * `:guild_member_join`
|
43
|
-
# * `:user_premium_guild_subscription`
|
44
|
-
# * `:user_premium_guild_subscription_tier_1`
|
45
|
-
# * `:user_premium_guild_subscription_tier_2`
|
46
|
-
# * `:user_premium_guild_subscription_tier_3`
|
47
|
-
# * `:channel_follow_add`
|
48
|
-
# * `:guild_discovery_disqualified`
|
49
|
-
# * `:guild_discovery_requalified`
|
50
|
-
# * `:guild_discovery_grace_period_initial_warning`
|
51
|
-
# * `:guild_discovery_grace_period_final_warning`
|
52
|
-
# * `:thread_created`
|
53
|
-
# * `:reply`
|
54
|
-
# * `:chat_input_command`
|
55
|
-
# * `:thread_starter_message`
|
56
|
-
# * `:guild_invite_reminder`
|
57
|
-
# * `:context_menu_command`
|
58
|
-
attr_reader :type
|
59
|
-
# @return [Discorb::Message::Activity] The activity of the message.
|
60
|
-
attr_reader :activity
|
61
|
-
# @return [Discorb::Application] The application of the message.
|
62
|
-
attr_reader :application_id
|
63
|
-
# @return [Discorb::Message::Reference] The reference of the message.
|
64
|
-
attr_reader :message_reference
|
65
|
-
# @return [Discorb::Message::Flag] The flag of the message.
|
66
|
-
# @see Discorb::Message::Flag
|
67
|
-
attr_reader :flag
|
68
|
-
# @return [Discorb::Message::Sticker] The sticker of the message.
|
69
|
-
attr_reader :stickers
|
70
|
-
# @return [Discorb::Message::Interaction] The interaction of the message.
|
71
|
-
attr_reader :interaction
|
72
|
-
# @return [Discorb::ThreadChannel] The thread channel of the message.
|
73
|
-
attr_reader :thread
|
74
|
-
# @return [Array<Array<Discorb::Component>>] The components of the message.
|
75
|
-
attr_reader :components
|
76
|
-
# @return [Boolean] Whether the message is deleted.
|
77
|
-
attr_reader :deleted
|
78
|
-
alias deleted? deleted
|
79
|
-
# @return [Boolean] Whether the message is tts.
|
80
|
-
attr_reader :tts
|
81
|
-
alias tts? tts
|
82
|
-
# @return [Boolean] Whether the message mentions everyone.
|
83
|
-
attr_reader :mention_everyone
|
84
|
-
alias mention_everyone? mention_everyone
|
85
|
-
# @return [Boolean] Whether the message is pinned.
|
86
|
-
attr_reader :pinned
|
87
|
-
alias pinned? pinned
|
88
|
-
# @private
|
89
|
-
# @return [{Integer => Symbol}] The mapping of message type.
|
90
|
-
MESSAGE_TYPE = {
|
91
|
-
0 => :default,
|
92
|
-
1 => :recipient_add,
|
93
|
-
2 => :recipient_remove,
|
94
|
-
3 => :call,
|
95
|
-
4 => :channel_name_change,
|
96
|
-
5 => :channel_icon_change,
|
97
|
-
6 => :channel_pinned_message,
|
98
|
-
7 => :guild_member_join,
|
99
|
-
8 => :user_premium_guild_subscription,
|
100
|
-
9 => :user_premium_guild_subscription_tier_1,
|
101
|
-
10 => :user_premium_guild_subscription_tier_2,
|
102
|
-
11 => :user_premium_guild_subscription_tier_3,
|
103
|
-
12 => :channel_follow_add,
|
104
|
-
14 => :guild_discovery_disqualified,
|
105
|
-
15 => :guild_discovery_requalified,
|
106
|
-
16 => :guild_discovery_grace_period_initial_warning,
|
107
|
-
17 => :guild_discovery_grace_period_final_warning,
|
108
|
-
18 => :thread_created,
|
109
|
-
19 => :reply,
|
110
|
-
20 => :chat_input_command,
|
111
|
-
21 => :thread_starter_message,
|
112
|
-
22 => :guild_invite_reminder,
|
113
|
-
23 => :context_menu_command
|
114
|
-
}.freeze
|
115
|
-
|
116
|
-
# @!attribute [r] channel
|
117
|
-
# @macro client_cache
|
118
|
-
# @return [Discorb::Channel] The channel the message was sent in.
|
119
|
-
# @!attribute [r] guild
|
120
|
-
# @macro client_cache
|
121
|
-
# @return [Discorb::Guild] The guild the message was sent in.
|
122
|
-
# @return [nil] If the message was not sent in a guild.
|
123
|
-
# @!attribute [r] webhook?
|
124
|
-
# @return [Boolean] Whether the message was sent by a webhook.
|
125
|
-
# @!attribute [r] edited?
|
126
|
-
# @return [Boolean] Whether the message was edited.
|
127
|
-
# @!attribute [r] jump_url
|
128
|
-
# @return [String] The URL to jump to the message.
|
129
|
-
# @!attribute [r] embed
|
130
|
-
# @return [Discorb::Embed] The embed of the message.
|
131
|
-
# @return [nil] If the message has no embed.
|
132
|
-
# @!attribute [r] embed?
|
133
|
-
# @return [Boolean] Whether the message has an embed.
|
134
|
-
# @!attribute [r] reply?
|
135
|
-
# @return [Boolean] Whether the message is a reply.
|
136
|
-
# @!attribute [r] dm?
|
137
|
-
# @return [Boolean] Whether the message was sent in a DM.
|
138
|
-
# @!attribute [r] guild?
|
139
|
-
# @return [Boolean] Whether the message was sent in a guild.
|
140
|
-
|
141
|
-
def embed?
|
142
|
-
@embeds.any?
|
143
|
-
end
|
144
|
-
|
145
|
-
def reply?
|
146
|
-
!@message_reference.nil?
|
147
|
-
end
|
148
|
-
|
149
|
-
def dm?
|
150
|
-
@guild_id.nil?
|
151
|
-
end
|
152
|
-
|
153
|
-
def guild?
|
154
|
-
!@guild_id.nil?
|
155
|
-
end
|
156
|
-
|
157
|
-
#
|
158
|
-
# Initialize a new message.
|
159
|
-
# @private
|
160
|
-
#
|
161
|
-
# @param [Discorb::Client] client The client.
|
162
|
-
# @param [Hash] data The data of the welcome screen.
|
163
|
-
# @param [Boolean] no_cache Whether to disable caching.
|
164
|
-
#
|
165
|
-
def initialize(client, data, no_cache: false)
|
166
|
-
@client = client
|
167
|
-
@data = {}
|
168
|
-
@no_cache = no_cache
|
169
|
-
_set_data(data)
|
170
|
-
@client.messages[@id] = self unless @no_cache
|
171
|
-
end
|
172
|
-
|
173
|
-
def channel
|
174
|
-
@dm || @client.channels[@channel_id]
|
175
|
-
end
|
176
|
-
|
177
|
-
def guild
|
178
|
-
@client.guilds[@guild_id]
|
179
|
-
end
|
180
|
-
|
181
|
-
def webhook?
|
182
|
-
@webhook_id != nil
|
183
|
-
end
|
184
|
-
|
185
|
-
def jump_url
|
186
|
-
"https://discord.com/channels/#{@guild_id || "@me"}/#{@channel_id}/#{@id}"
|
187
|
-
end
|
188
|
-
|
189
|
-
def edited?
|
190
|
-
!@updated_at.nil?
|
191
|
-
end
|
192
|
-
|
193
|
-
#
|
194
|
-
# Removes the mentions from the message.
|
195
|
-
#
|
196
|
-
# @param [Boolean] user Whether to clean user mentions.
|
197
|
-
# @param [Boolean] channel Whether to clean channel mentions.
|
198
|
-
# @param [Boolean] role Whether to clean role mentions.
|
199
|
-
# @param [Boolean] emoji Whether to clean emoji.
|
200
|
-
# @param [Boolean] everyone Whether to clean `@everyone` and `@here`.
|
201
|
-
# @param [Boolean] codeblock Whether to clean codeblocks.
|
202
|
-
#
|
203
|
-
# @return [String] The cleaned content of the message.
|
204
|
-
#
|
205
|
-
def clean_content(
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
#
|
254
|
-
#
|
255
|
-
# @
|
256
|
-
#
|
257
|
-
# @param [
|
258
|
-
# @param [
|
259
|
-
#
|
260
|
-
# @
|
261
|
-
#
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
#
|
292
|
-
#
|
293
|
-
#
|
294
|
-
# @param [
|
295
|
-
#
|
296
|
-
# @return [
|
297
|
-
#
|
298
|
-
def
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
def
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
#
|
325
|
-
# @async
|
326
|
-
#
|
327
|
-
# @return [Async::Task<
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
#
|
336
|
-
#
|
337
|
-
#
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
#
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
#
|
375
|
-
#
|
376
|
-
#
|
377
|
-
#
|
378
|
-
#
|
379
|
-
# @
|
380
|
-
#
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
#
|
402
|
-
#
|
403
|
-
# @
|
404
|
-
#
|
405
|
-
# @
|
406
|
-
#
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
@
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
@
|
540
|
-
@data
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Discorb
|
4
|
+
#
|
5
|
+
# Represents a message.
|
6
|
+
#
|
7
|
+
class Message < DiscordModel
|
8
|
+
# @return [Discorb::Snowflake] The ID of the message.
|
9
|
+
attr_reader :id
|
10
|
+
# @return [Discorb::User, Discorb::Member, Webhook::Message::Author] The user that sent the message.
|
11
|
+
attr_reader :author
|
12
|
+
# @return [String] The content of the message.
|
13
|
+
attr_reader :content
|
14
|
+
alias to_s content
|
15
|
+
# @return [Time] The time the message was created.
|
16
|
+
attr_reader :created_at
|
17
|
+
alias timestamp created_at
|
18
|
+
alias sent_at created_at
|
19
|
+
# @return [Time] The time the message was edited.
|
20
|
+
# @return [nil] If the message was not edited.
|
21
|
+
attr_reader :updated_at
|
22
|
+
alias edited_at updated_at
|
23
|
+
alias edited_timestamp updated_at
|
24
|
+
# @return [Array<Discorb::Attachment>] The attachments of the message.
|
25
|
+
attr_reader :attachments
|
26
|
+
# @return [Array<Discorb::Embed>] The embeds of the message.
|
27
|
+
attr_reader :embeds
|
28
|
+
# @return [Array<Discorb::Reaction>] The reactions of the message.
|
29
|
+
attr_reader :reactions
|
30
|
+
# @return [Discorb::Snowflake] The ID of the channel the message was sent in.
|
31
|
+
attr_reader :webhook_id
|
32
|
+
# @return [Symbol] The type of the message.
|
33
|
+
# Currently, this will be one of:
|
34
|
+
#
|
35
|
+
# * `:default`
|
36
|
+
# * `:recipient_add`
|
37
|
+
# * `:recipient_remove`
|
38
|
+
# * `:call`
|
39
|
+
# * `:channel_name_change`
|
40
|
+
# * `:channel_icon_change`
|
41
|
+
# * `:channel_pinned_message`
|
42
|
+
# * `:guild_member_join`
|
43
|
+
# * `:user_premium_guild_subscription`
|
44
|
+
# * `:user_premium_guild_subscription_tier_1`
|
45
|
+
# * `:user_premium_guild_subscription_tier_2`
|
46
|
+
# * `:user_premium_guild_subscription_tier_3`
|
47
|
+
# * `:channel_follow_add`
|
48
|
+
# * `:guild_discovery_disqualified`
|
49
|
+
# * `:guild_discovery_requalified`
|
50
|
+
# * `:guild_discovery_grace_period_initial_warning`
|
51
|
+
# * `:guild_discovery_grace_period_final_warning`
|
52
|
+
# * `:thread_created`
|
53
|
+
# * `:reply`
|
54
|
+
# * `:chat_input_command`
|
55
|
+
# * `:thread_starter_message`
|
56
|
+
# * `:guild_invite_reminder`
|
57
|
+
# * `:context_menu_command`
|
58
|
+
attr_reader :type
|
59
|
+
# @return [Discorb::Message::Activity] The activity of the message.
|
60
|
+
attr_reader :activity
|
61
|
+
# @return [Discorb::Application] The application of the message.
|
62
|
+
attr_reader :application_id
|
63
|
+
# @return [Discorb::Message::Reference] The reference of the message.
|
64
|
+
attr_reader :message_reference
|
65
|
+
# @return [Discorb::Message::Flag] The flag of the message.
|
66
|
+
# @see Discorb::Message::Flag
|
67
|
+
attr_reader :flag
|
68
|
+
# @return [Discorb::Message::Sticker] The sticker of the message.
|
69
|
+
attr_reader :stickers
|
70
|
+
# @return [Discorb::Message::Interaction] The interaction of the message.
|
71
|
+
attr_reader :interaction
|
72
|
+
# @return [Discorb::ThreadChannel] The thread channel of the message.
|
73
|
+
attr_reader :thread
|
74
|
+
# @return [Array<Array<Discorb::Component>>] The components of the message.
|
75
|
+
attr_reader :components
|
76
|
+
# @return [Boolean] Whether the message is deleted.
|
77
|
+
attr_reader :deleted
|
78
|
+
alias deleted? deleted
|
79
|
+
# @return [Boolean] Whether the message is tts.
|
80
|
+
attr_reader :tts
|
81
|
+
alias tts? tts
|
82
|
+
# @return [Boolean] Whether the message mentions everyone.
|
83
|
+
attr_reader :mention_everyone
|
84
|
+
alias mention_everyone? mention_everyone
|
85
|
+
# @return [Boolean] Whether the message is pinned.
|
86
|
+
attr_reader :pinned
|
87
|
+
alias pinned? pinned
|
88
|
+
# @private
|
89
|
+
# @return [{Integer => Symbol}] The mapping of message type.
|
90
|
+
MESSAGE_TYPE = {
|
91
|
+
0 => :default,
|
92
|
+
1 => :recipient_add,
|
93
|
+
2 => :recipient_remove,
|
94
|
+
3 => :call,
|
95
|
+
4 => :channel_name_change,
|
96
|
+
5 => :channel_icon_change,
|
97
|
+
6 => :channel_pinned_message,
|
98
|
+
7 => :guild_member_join,
|
99
|
+
8 => :user_premium_guild_subscription,
|
100
|
+
9 => :user_premium_guild_subscription_tier_1,
|
101
|
+
10 => :user_premium_guild_subscription_tier_2,
|
102
|
+
11 => :user_premium_guild_subscription_tier_3,
|
103
|
+
12 => :channel_follow_add,
|
104
|
+
14 => :guild_discovery_disqualified,
|
105
|
+
15 => :guild_discovery_requalified,
|
106
|
+
16 => :guild_discovery_grace_period_initial_warning,
|
107
|
+
17 => :guild_discovery_grace_period_final_warning,
|
108
|
+
18 => :thread_created,
|
109
|
+
19 => :reply,
|
110
|
+
20 => :chat_input_command,
|
111
|
+
21 => :thread_starter_message,
|
112
|
+
22 => :guild_invite_reminder,
|
113
|
+
23 => :context_menu_command
|
114
|
+
}.freeze
|
115
|
+
|
116
|
+
# @!attribute [r] channel
|
117
|
+
# @macro client_cache
|
118
|
+
# @return [Discorb::Channel] The channel the message was sent in.
|
119
|
+
# @!attribute [r] guild
|
120
|
+
# @macro client_cache
|
121
|
+
# @return [Discorb::Guild] The guild the message was sent in.
|
122
|
+
# @return [nil] If the message was not sent in a guild.
|
123
|
+
# @!attribute [r] webhook?
|
124
|
+
# @return [Boolean] Whether the message was sent by a webhook.
|
125
|
+
# @!attribute [r] edited?
|
126
|
+
# @return [Boolean] Whether the message was edited.
|
127
|
+
# @!attribute [r] jump_url
|
128
|
+
# @return [String] The URL to jump to the message.
|
129
|
+
# @!attribute [r] embed
|
130
|
+
# @return [Discorb::Embed] The embed of the message.
|
131
|
+
# @return [nil] If the message has no embed.
|
132
|
+
# @!attribute [r] embed?
|
133
|
+
# @return [Boolean] Whether the message has an embed.
|
134
|
+
# @!attribute [r] reply?
|
135
|
+
# @return [Boolean] Whether the message is a reply.
|
136
|
+
# @!attribute [r] dm?
|
137
|
+
# @return [Boolean] Whether the message was sent in a DM.
|
138
|
+
# @!attribute [r] guild?
|
139
|
+
# @return [Boolean] Whether the message was sent in a guild.
|
140
|
+
|
141
|
+
def embed?
|
142
|
+
@embeds.any?
|
143
|
+
end
|
144
|
+
|
145
|
+
def reply?
|
146
|
+
!@message_reference.nil?
|
147
|
+
end
|
148
|
+
|
149
|
+
def dm?
|
150
|
+
@guild_id.nil?
|
151
|
+
end
|
152
|
+
|
153
|
+
def guild?
|
154
|
+
!@guild_id.nil?
|
155
|
+
end
|
156
|
+
|
157
|
+
#
|
158
|
+
# Initialize a new message.
|
159
|
+
# @private
|
160
|
+
#
|
161
|
+
# @param [Discorb::Client] client The client.
|
162
|
+
# @param [Hash] data The data of the welcome screen.
|
163
|
+
# @param [Boolean] no_cache Whether to disable caching.
|
164
|
+
#
|
165
|
+
def initialize(client, data, no_cache: false)
|
166
|
+
@client = client
|
167
|
+
@data = {}
|
168
|
+
@no_cache = no_cache
|
169
|
+
_set_data(data)
|
170
|
+
@client.messages[@id] = self unless @no_cache
|
171
|
+
end
|
172
|
+
|
173
|
+
def channel
|
174
|
+
@dm || @client.channels[@channel_id]
|
175
|
+
end
|
176
|
+
|
177
|
+
def guild
|
178
|
+
@client.guilds[@guild_id]
|
179
|
+
end
|
180
|
+
|
181
|
+
def webhook?
|
182
|
+
@webhook_id != nil
|
183
|
+
end
|
184
|
+
|
185
|
+
def jump_url
|
186
|
+
"https://discord.com/channels/#{@guild_id || "@me"}/#{@channel_id}/#{@id}"
|
187
|
+
end
|
188
|
+
|
189
|
+
def edited?
|
190
|
+
!@updated_at.nil?
|
191
|
+
end
|
192
|
+
|
193
|
+
#
|
194
|
+
# Removes the mentions from the message.
|
195
|
+
#
|
196
|
+
# @param [Boolean] user Whether to clean user mentions.
|
197
|
+
# @param [Boolean] channel Whether to clean channel mentions.
|
198
|
+
# @param [Boolean] role Whether to clean role mentions.
|
199
|
+
# @param [Boolean] emoji Whether to clean emoji.
|
200
|
+
# @param [Boolean] everyone Whether to clean `@everyone` and `@here`.
|
201
|
+
# @param [Boolean] codeblock Whether to clean codeblocks.
|
202
|
+
#
|
203
|
+
# @return [String] The cleaned content of the message.
|
204
|
+
#
|
205
|
+
def clean_content(
|
206
|
+
user: true,
|
207
|
+
channel: true,
|
208
|
+
role: true,
|
209
|
+
emoji: true,
|
210
|
+
everyone: true,
|
211
|
+
codeblock: false
|
212
|
+
)
|
213
|
+
ret = @content.dup
|
214
|
+
if user
|
215
|
+
ret.gsub!(/<@!?(\d+)>/) do |_match|
|
216
|
+
member = guild&.members&.[](Regexp.last_match(1))
|
217
|
+
member ||= @client.users[Regexp.last_match(1)]
|
218
|
+
member ? "@#{member.name}" : "@Unknown User"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
ret.gsub!(/<#(\d+)>/) do |_match|
|
222
|
+
channel = @client.channels[Regexp.last_match(1)]
|
223
|
+
channel ? "<##{channel.id}>" : "#Unknown Channel"
|
224
|
+
end
|
225
|
+
if role
|
226
|
+
ret.gsub!(/<@&(\d+)>/) do |_match|
|
227
|
+
r = guild&.roles&.[](Regexp.last_match(1))
|
228
|
+
r ? "@#{r.name}" : "@Unknown Role"
|
229
|
+
end
|
230
|
+
end
|
231
|
+
if emoji
|
232
|
+
ret.gsub!(/<a?:([a-zA-Z0-9_]+):\d+>/) { |_match| Regexp.last_match(1) }
|
233
|
+
end
|
234
|
+
ret.gsub!(/@(everyone|here)/, "@\u200b\\1") if everyone
|
235
|
+
if codeblock
|
236
|
+
ret
|
237
|
+
else
|
238
|
+
codeblocks = ret.split("```", -1)
|
239
|
+
original_codeblocks = @content.scan(/```(.+?)```/m)
|
240
|
+
res = []
|
241
|
+
max = codeblocks.length
|
242
|
+
codeblocks.each_with_index do |single_codeblock, i|
|
243
|
+
res << if (max.even? && i == max - 1) || i.even?
|
244
|
+
single_codeblock
|
245
|
+
else
|
246
|
+
original_codeblocks[i / 2]
|
247
|
+
end
|
248
|
+
end
|
249
|
+
res.join("```")
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
#
|
254
|
+
# Edit the message.
|
255
|
+
# @async
|
256
|
+
#
|
257
|
+
# @param [String] content The message content.
|
258
|
+
# @param [Discorb::Embed] embed The embed to send.
|
259
|
+
# @param [Array<Discorb::Embed>] embeds The embeds to send.
|
260
|
+
# @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions.
|
261
|
+
# @param [Array<Discorb::Attachment>] attachments The new attachments.
|
262
|
+
# @param [Array<Discorb::Component>, Array<Array<Discorb::Component>>] components The components to send.
|
263
|
+
# @param [Boolean] supress Whether to supress embeds.
|
264
|
+
#
|
265
|
+
# @return [Async::Task<void>] The task.
|
266
|
+
#
|
267
|
+
def edit(
|
268
|
+
content = Discorb::Unset,
|
269
|
+
embed: Discorb::Unset,
|
270
|
+
embeds: Discorb::Unset,
|
271
|
+
allowed_mentions: Discorb::Unset,
|
272
|
+
attachments: Discorb::Unset,
|
273
|
+
components: Discorb::Unset,
|
274
|
+
supress: Discorb::Unset
|
275
|
+
)
|
276
|
+
Async do
|
277
|
+
channel.edit_message(
|
278
|
+
@id,
|
279
|
+
content,
|
280
|
+
embed: embed,
|
281
|
+
embeds: embeds,
|
282
|
+
allowed_mentions: allowed_mentions,
|
283
|
+
attachments: attachments,
|
284
|
+
components: components,
|
285
|
+
supress: supress
|
286
|
+
).wait
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
#
|
291
|
+
# Delete the message.
|
292
|
+
# @async
|
293
|
+
#
|
294
|
+
# @param [String] reason The reason for deleting the message.
|
295
|
+
#
|
296
|
+
# @return [Async::Task<void>] The task.
|
297
|
+
#
|
298
|
+
def delete(reason: nil)
|
299
|
+
Async { channel.delete_message(@id, reason: reason).wait }
|
300
|
+
end
|
301
|
+
|
302
|
+
#
|
303
|
+
# Convert the message to reference object.
|
304
|
+
#
|
305
|
+
# @param [Boolean] fail_if_not_exists Whether to raise an error if the message does not exist.
|
306
|
+
#
|
307
|
+
# @return [Discorb::Message::Reference] The reference object.
|
308
|
+
#
|
309
|
+
def to_reference(fail_if_not_exists: true)
|
310
|
+
Reference.from_hash(
|
311
|
+
{
|
312
|
+
message_id: @id,
|
313
|
+
channel_id: @channel_id,
|
314
|
+
guild_id: @guild_id,
|
315
|
+
fail_if_not_exists: fail_if_not_exists
|
316
|
+
}
|
317
|
+
)
|
318
|
+
end
|
319
|
+
|
320
|
+
def embed
|
321
|
+
@embeds[0]
|
322
|
+
end
|
323
|
+
|
324
|
+
# Reply to the message.
|
325
|
+
# @async
|
326
|
+
# @param (see #post)
|
327
|
+
# @return [Async::Task<Discorb::Message>] The message.
|
328
|
+
def reply(*args, **kwargs)
|
329
|
+
Async { channel.post(*args, reference: self, **kwargs).wait }
|
330
|
+
end
|
331
|
+
|
332
|
+
#
|
333
|
+
# Publish the message.
|
334
|
+
# @async
|
335
|
+
#
|
336
|
+
# @return [Async::Task<void>] The task.
|
337
|
+
#
|
338
|
+
def publish
|
339
|
+
Async do
|
340
|
+
channel.post(
|
341
|
+
"/channels/#{@channel_id}/messages/#{@id}/crosspost",
|
342
|
+
nil
|
343
|
+
).wait
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
#
|
348
|
+
# Add a reaction to the message.
|
349
|
+
# @async
|
350
|
+
#
|
351
|
+
# @param [Discorb::Emoji] emoji The emoji to react with.
|
352
|
+
#
|
353
|
+
# @return [Async::Task<void>] The task.
|
354
|
+
#
|
355
|
+
def add_reaction(emoji)
|
356
|
+
Async do
|
357
|
+
@client
|
358
|
+
.http
|
359
|
+
.request(
|
360
|
+
Route.new(
|
361
|
+
"/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}/@me",
|
362
|
+
"//channels/:channel_id/messages/:message_id/reactions/:emoji/@me",
|
363
|
+
:put
|
364
|
+
),
|
365
|
+
nil
|
366
|
+
)
|
367
|
+
.wait
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
alias react_with add_reaction
|
372
|
+
|
373
|
+
#
|
374
|
+
# Remove a reaction from the message.
|
375
|
+
# @async
|
376
|
+
#
|
377
|
+
# @param [Discorb::Emoji] emoji The emoji to remove.
|
378
|
+
#
|
379
|
+
# @return [Async::Task<void>] The task.
|
380
|
+
#
|
381
|
+
def remove_reaction(emoji)
|
382
|
+
Async do
|
383
|
+
@client
|
384
|
+
.http
|
385
|
+
.request(
|
386
|
+
Route.new(
|
387
|
+
"/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}/@me",
|
388
|
+
"//channels/:channel_id/messages/:message_id/reactions/:emoji/@me",
|
389
|
+
:delete
|
390
|
+
)
|
391
|
+
)
|
392
|
+
.wait
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
alias delete_reaction remove_reaction
|
397
|
+
|
398
|
+
#
|
399
|
+
# Remove other member's reaction from the message.
|
400
|
+
# @async
|
401
|
+
#
|
402
|
+
# @param [Discorb::Emoji] emoji The emoji to remove.
|
403
|
+
# @param [Discorb::Member] member The member to remove the reaction from.
|
404
|
+
#
|
405
|
+
# @return [Async::Task<void>] The task.
|
406
|
+
#
|
407
|
+
def remove_reaction_of(emoji, member)
|
408
|
+
Async do
|
409
|
+
@client
|
410
|
+
.http
|
411
|
+
.request(
|
412
|
+
Route.new(
|
413
|
+
"/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}/#{
|
414
|
+
member.is_a?(Member) ? member.id : member
|
415
|
+
}",
|
416
|
+
"//channels/:channel_id/messages/:message_id/reactions/:emoji/:user_id",
|
417
|
+
:delete
|
418
|
+
)
|
419
|
+
)
|
420
|
+
.wait
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
alias delete_reaction_of remove_reaction_of
|
425
|
+
|
426
|
+
#
|
427
|
+
# Fetch reacted users of reaction.
|
428
|
+
# @async
|
429
|
+
#
|
430
|
+
# @param [Discorb::Emoji, Discorb::PartialEmoji] emoji The emoji to fetch.
|
431
|
+
# @param [Integer, nil] limit The maximum number of users to fetch. `nil` for no limit.
|
432
|
+
# @param [Discorb::Snowflake, nil] after The ID of the user to start fetching from.
|
433
|
+
#
|
434
|
+
# @return [Async::Task<Array<Discorb::User>>] The users.
|
435
|
+
#
|
436
|
+
def fetch_reacted_users(
|
437
|
+
emoji,
|
438
|
+
limit: nil,
|
439
|
+
after: Discorb::Snowflake.new("0")
|
440
|
+
)
|
441
|
+
Async do
|
442
|
+
if limit.nil? || !limit.positive?
|
443
|
+
after = Discorb::Snowflake.new("0")
|
444
|
+
users = []
|
445
|
+
loop do
|
446
|
+
_resp, data =
|
447
|
+
@client
|
448
|
+
.http
|
449
|
+
.request(
|
450
|
+
Route.new(
|
451
|
+
"/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}?limit=100&after=#{after}",
|
452
|
+
"//channels/:channel_id/messages/:message_id/reactions/:emoji",
|
453
|
+
:get
|
454
|
+
)
|
455
|
+
)
|
456
|
+
.wait
|
457
|
+
break if data.empty?
|
458
|
+
|
459
|
+
users +=
|
460
|
+
data.map do |r|
|
461
|
+
guild&.members&.[](r[:id]) || @client.users[r[:id]] ||
|
462
|
+
User.new(@client, r)
|
463
|
+
end
|
464
|
+
|
465
|
+
break if data.length < 100
|
466
|
+
|
467
|
+
after = data[-1][:id]
|
468
|
+
end
|
469
|
+
next users
|
470
|
+
else
|
471
|
+
_resp, data =
|
472
|
+
@client
|
473
|
+
.http
|
474
|
+
.request(
|
475
|
+
Route.new(
|
476
|
+
"/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}?limit=#{limit}&after=#{after}",
|
477
|
+
"//channels/:channel_id/messages/:message_id/reactions/:emoji",
|
478
|
+
:get
|
479
|
+
)
|
480
|
+
)
|
481
|
+
.wait
|
482
|
+
next(
|
483
|
+
data.map do |r|
|
484
|
+
guild&.members&.[](r[:id]) || @client.users[r[:id]] ||
|
485
|
+
User.new(@client, r)
|
486
|
+
end
|
487
|
+
)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
#
|
493
|
+
# Pin the message.
|
494
|
+
# @async
|
495
|
+
#
|
496
|
+
# @param [String] reason The reason for pinning the message.
|
497
|
+
#
|
498
|
+
# @return [Async::Task<void>] The task.
|
499
|
+
#
|
500
|
+
def pin(reason: nil)
|
501
|
+
Async { channel.pin_message(self, reason: reason).wait }
|
502
|
+
end
|
503
|
+
|
504
|
+
#
|
505
|
+
# Unpin the message.
|
506
|
+
# @async
|
507
|
+
#
|
508
|
+
# @param [String] reason The reason for unpinning the message.
|
509
|
+
#
|
510
|
+
# @return [Async::Task<void>] The task.
|
511
|
+
#
|
512
|
+
def unpin(reason: nil)
|
513
|
+
Async { channel.unpin_message(self, reason: reason).wait }
|
514
|
+
end
|
515
|
+
|
516
|
+
#
|
517
|
+
# Start thread from the message.
|
518
|
+
# @async
|
519
|
+
#
|
520
|
+
# @param (see Discorb::Channel#start_thread)
|
521
|
+
#
|
522
|
+
# @return [Async::Task<Discorb::ThreadChannel>] <description>
|
523
|
+
#
|
524
|
+
def start_thread(*args, **kwargs)
|
525
|
+
Async { channel.start_thread(*args, message: self, **kwargs).wait }
|
526
|
+
end
|
527
|
+
|
528
|
+
alias create_thread start_thread
|
529
|
+
|
530
|
+
# Meta
|
531
|
+
|
532
|
+
def inspect
|
533
|
+
"#<#{self.class} #{@content.inspect} id=#{@id}>"
|
534
|
+
end
|
535
|
+
|
536
|
+
private
|
537
|
+
|
538
|
+
def _set_data(data)
|
539
|
+
@id = Snowflake.new(data[:id])
|
540
|
+
@channel_id = data[:channel_id]
|
541
|
+
|
542
|
+
if data[:guild_id]
|
543
|
+
@guild_id = data[:guild_id]
|
544
|
+
@dm = nil
|
545
|
+
else
|
546
|
+
@dm = Discorb::DMChannel.new(@client, data[:channel_id])
|
547
|
+
@guild_id = nil
|
548
|
+
end
|
549
|
+
|
550
|
+
if data[:member].nil? && data[:webhook_id]
|
551
|
+
@webhook_id = Snowflake.new(data[:webhook_id])
|
552
|
+
@author = Webhook::Message::Author.new(data[:author])
|
553
|
+
elsif data[:guild_id].nil? || data[:guild_id].empty? || data[:member].nil?
|
554
|
+
@author =
|
555
|
+
@client.users[data[:author][:id]] || User.new(@client, data[:author])
|
556
|
+
else
|
557
|
+
@author =
|
558
|
+
guild&.members&.get(data[:author][:id]) ||
|
559
|
+
Member.new(@client, @guild_id, data[:author], data[:member])
|
560
|
+
end
|
561
|
+
@content = data[:content]
|
562
|
+
@created_at = Time.iso8601(data[:timestamp])
|
563
|
+
@updated_at =
|
564
|
+
(
|
565
|
+
if data[:edited_timestamp].nil?
|
566
|
+
nil
|
567
|
+
else
|
568
|
+
Time.iso8601(data[:edited_timestamp])
|
569
|
+
end
|
570
|
+
)
|
571
|
+
|
572
|
+
@tts = data[:tts]
|
573
|
+
@mention_everyone = data[:mention_everyone]
|
574
|
+
@mention_roles = data[:mention_roles].map { |r| guild.roles[r] }
|
575
|
+
@attachments = data[:attachments].map { |a| Attachment.from_hash(a) }
|
576
|
+
@embeds =
|
577
|
+
data[:embeds] ? data[:embeds].map { |e| Embed.from_hash(e) } : []
|
578
|
+
@reactions =
|
579
|
+
(
|
580
|
+
if data[:reactions]
|
581
|
+
data[:reactions].map { |r| Reaction.new(self, r) }
|
582
|
+
else
|
583
|
+
[]
|
584
|
+
end
|
585
|
+
)
|
586
|
+
@pinned = data[:pinned]
|
587
|
+
@type = MESSAGE_TYPE[data[:type]]
|
588
|
+
@activity = data[:activity] && Activity.new(data[:activity])
|
589
|
+
@application_id = data[:application_id]
|
590
|
+
@message_reference =
|
591
|
+
data[:message_reference] &&
|
592
|
+
Reference.from_hash(data[:message_reference])
|
593
|
+
@flag = Flag.new(0b111 - data[:flags])
|
594
|
+
@sticker_items =
|
595
|
+
(
|
596
|
+
if data[:sticker_items]
|
597
|
+
data[:sticker_items].map { |s| Message::Sticker.new(s) }
|
598
|
+
else
|
599
|
+
[]
|
600
|
+
end
|
601
|
+
)
|
602
|
+
# @referenced_message = data[:referenced_message] && Message.new(@client, data[:referenced_message])
|
603
|
+
@interaction =
|
604
|
+
data[:interaction] &&
|
605
|
+
Message::Interaction.new(@client, data[:interaction])
|
606
|
+
@thread = data[:thread] && Channel.make_channel(@client, data[:thread])
|
607
|
+
@components =
|
608
|
+
data[:components].map do |c|
|
609
|
+
c[:components].map { |co| Component.from_hash(co) }
|
610
|
+
end
|
611
|
+
@data.update(data)
|
612
|
+
@deleted = false
|
613
|
+
end
|
614
|
+
end
|
615
|
+
end
|