telegem 3.3.0 → 3.4.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/.rubocop.yml +57 -0
- data/CHANGELOG.md +121 -0
- data/Gemfile +1 -1
- data/README.md +147 -0
- data/bin/telegem-ssl +71 -25
- data/contributing.md +375 -0
- data/docs/api.md +663 -0
- data/docs/bot.md +332 -0
- data/docs/changelog.md +182 -0
- data/docs/context.md +554 -0
- data/docs/core_concepts.md +218 -0
- data/docs/deployment.md +702 -0
- data/docs/error_handling.md +435 -0
- data/docs/examples.md +752 -0
- data/docs/getting_started.md +151 -0
- data/docs/handlers.md +580 -0
- data/docs/keyboards.md +446 -0
- data/docs/middleware.md +536 -0
- data/docs/plugins.md +384 -0
- data/docs/scenes.md +517 -0
- data/docs/sessions.md +544 -0
- data/docs/testing.md +612 -0
- data/docs/troubleshooting.md +574 -0
- data/docs/types.md +538 -0
- data/docs/webhooks.md +456 -0
- data/lib/api/client.rb +38 -10
- data/lib/api/types.rb +433 -172
- data/lib/core/composer.rb +3 -3
- data/lib/core/context.rb +17 -11
- data/lib/plugins/cc +3 -0
- data/lib/plugins/file_extract.rb +2 -2
- data/lib/plugins/translate.rb +43 -0
- data/lib/session/memory_store.rb +90 -103
- data/lib/session/redis.rb +91 -0
- data/lib/telegem.rb +4 -4
- data/lib/webhook/server.rb +5 -3
- metadata +51 -35
- data/CHANGELOG +0 -95
- data/Contributing.md +0 -161
- data/Readme.md +0 -302
- data/examples/.gitkeep +0 -0
- data/public/.gitkeep +0 -0
data/lib/api/types.rb
CHANGED
|
@@ -5,91 +5,106 @@ module Telegem
|
|
|
5
5
|
@_raw_data = data || {}
|
|
6
6
|
@_accessors_defined = {}
|
|
7
7
|
end
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
def method_missing(name, *args)
|
|
10
10
|
return super if args.any? || block_given?
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
define_accessor(name)
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
if respond_to?(name)
|
|
15
15
|
send(name)
|
|
16
16
|
else
|
|
17
17
|
super
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
def respond_to_missing?(name, include_private = false)
|
|
22
22
|
key = name.to_s
|
|
23
23
|
camel_key = snake_to_camel(key)
|
|
24
24
|
@_raw_data.key?(key) || @_raw_data.key?(camel_key) || super
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
def to_h
|
|
28
28
|
@_raw_data.dup
|
|
29
29
|
end
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
alias_method :to_hash, :to_h
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
def inspect
|
|
34
34
|
"#<#{self.class.name} #{@_raw_data.inspect}>"
|
|
35
35
|
end
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
def to_s
|
|
38
38
|
inspect
|
|
39
39
|
end
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
attr_reader :_raw_data
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
private
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
def define_accessor(name)
|
|
46
46
|
return if @_accessors_defined[name]
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
key = name.to_s
|
|
49
49
|
camel_key = snake_to_camel(key)
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
if @_raw_data.key?(key)
|
|
52
52
|
define_singleton_method(name) { @_raw_data[key] }
|
|
53
53
|
elsif @_raw_data.key?(camel_key)
|
|
54
54
|
define_singleton_method(name) { @_raw_data[camel_key] }
|
|
55
55
|
else
|
|
56
56
|
define_singleton_method(name) do
|
|
57
|
-
raise NoMethodError,
|
|
57
|
+
raise NoMethodError,
|
|
58
58
|
"undefined method `#{name}' for #{self.class} with keys: #{@_raw_data.keys}"
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
@_accessors_defined[name] = true
|
|
63
63
|
end
|
|
64
|
-
|
|
64
|
+
|
|
65
|
+
# helpers for converting nested objects
|
|
66
|
+
def wrap(key, klass)
|
|
67
|
+
if @_raw_data[key] && !@_raw_data[key].is_a?(klass)
|
|
68
|
+
@_raw_data[key] = klass.new(@_raw_data[key])
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def wrap_array(key, klass)
|
|
73
|
+
if @_raw_data[key] && @_raw_data[key].is_a?(Array)
|
|
74
|
+
@_raw_data[key] = @_raw_data[key].map do |v|
|
|
75
|
+
v.is_a?(klass) ? v : klass.new(v)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
65
80
|
def snake_to_camel(str)
|
|
66
81
|
str.gsub(/_([a-z])/) { $1.upcase }
|
|
67
82
|
end
|
|
68
|
-
|
|
83
|
+
|
|
69
84
|
def camel_to_snake(str)
|
|
70
85
|
str.gsub(/([A-Z])/) { "_#{$1.downcase}" }.sub(/^_/, '')
|
|
71
86
|
end
|
|
72
87
|
end
|
|
73
|
-
|
|
88
|
+
|
|
74
89
|
class User < BaseType
|
|
75
90
|
COMMON_FIELDS = %w[id is_bot first_name last_name username
|
|
76
|
-
can_join_groups can_read_all_group_messages
|
|
77
|
-
supports_inline_queries language_code
|
|
78
|
-
is_premium added_to_attachment_menu
|
|
79
|
-
can_connect_to_business].freeze
|
|
80
|
-
|
|
91
|
+
can_join_groups can_read_all_group_messages
|
|
92
|
+
supports_inline_queries language_code
|
|
93
|
+
is_premium added_to_attachment_menu
|
|
94
|
+
can_connect_to_business can_manage_bots].freeze
|
|
95
|
+
|
|
81
96
|
def initialize(data)
|
|
82
97
|
super(data)
|
|
83
|
-
|
|
98
|
+
|
|
84
99
|
COMMON_FIELDS.each do |field|
|
|
85
100
|
define_accessor(field.to_sym)
|
|
86
101
|
end
|
|
87
102
|
end
|
|
88
|
-
|
|
103
|
+
|
|
89
104
|
def full_name
|
|
90
105
|
[first_name, last_name].compact.join(' ')
|
|
91
106
|
end
|
|
92
|
-
|
|
107
|
+
|
|
93
108
|
def mention
|
|
94
109
|
if username
|
|
95
110
|
"@#{username}"
|
|
@@ -99,127 +114,127 @@ module Telegem
|
|
|
99
114
|
"User ##{id}"
|
|
100
115
|
end
|
|
101
116
|
end
|
|
102
|
-
|
|
117
|
+
|
|
103
118
|
def to_s
|
|
104
119
|
full_name
|
|
105
120
|
end
|
|
106
121
|
end
|
|
107
|
-
|
|
122
|
+
|
|
108
123
|
class Chat < BaseType
|
|
109
124
|
COMMON_FIELDS = %w[id type username title first_name last_name
|
|
110
|
-
photo bio has_private_forwards
|
|
125
|
+
photo bio has_private_forwards
|
|
111
126
|
has_restricted_voice_and_video_messages
|
|
112
|
-
description invite_link pinned_message
|
|
127
|
+
description invite_link pinned_message
|
|
113
128
|
permissions slow_mode_delay message_auto_delete_time
|
|
114
|
-
has_protected_content sticker_set_name
|
|
129
|
+
has_protected_content sticker_set_name
|
|
115
130
|
can_set_sticker_set linked_chat_id location].freeze
|
|
116
|
-
|
|
131
|
+
|
|
117
132
|
def initialize(data)
|
|
118
133
|
super(data)
|
|
119
|
-
|
|
134
|
+
|
|
120
135
|
COMMON_FIELDS.each do |field|
|
|
121
136
|
define_accessor(field.to_sym)
|
|
122
137
|
end
|
|
123
138
|
end
|
|
124
|
-
|
|
139
|
+
|
|
125
140
|
def private?
|
|
126
141
|
type == 'private'
|
|
127
142
|
end
|
|
128
|
-
|
|
143
|
+
|
|
129
144
|
def group?
|
|
130
145
|
type == 'group'
|
|
131
146
|
end
|
|
132
|
-
|
|
147
|
+
|
|
133
148
|
def supergroup?
|
|
134
149
|
type == 'supergroup'
|
|
135
150
|
end
|
|
136
|
-
|
|
151
|
+
|
|
137
152
|
def channel?
|
|
138
153
|
type == 'channel'
|
|
139
154
|
end
|
|
140
|
-
|
|
155
|
+
|
|
141
156
|
def to_s
|
|
142
157
|
title || username || "Chat ##{id}"
|
|
143
158
|
end
|
|
144
159
|
end
|
|
145
|
-
|
|
160
|
+
|
|
146
161
|
class MessageEntity < BaseType
|
|
147
162
|
COMMON_FIELDS = %w[type offset length url user language
|
|
148
163
|
custom_emoji_id].freeze
|
|
149
|
-
|
|
164
|
+
|
|
150
165
|
def initialize(data)
|
|
151
166
|
super(data)
|
|
152
|
-
|
|
167
|
+
|
|
153
168
|
COMMON_FIELDS.each do |field|
|
|
154
169
|
define_accessor(field.to_sym)
|
|
155
170
|
end
|
|
156
|
-
|
|
171
|
+
|
|
157
172
|
if @_raw_data['user'] && !@_raw_data['user'].is_a?(User)
|
|
158
173
|
@_raw_data['user'] = User.new(@_raw_data['user'])
|
|
159
174
|
end
|
|
160
175
|
end
|
|
161
176
|
end
|
|
162
|
-
|
|
177
|
+
|
|
163
178
|
class Message < BaseType
|
|
164
|
-
COMMON_FIELDS = %w[message_id from chat date edit_date
|
|
165
|
-
text caption entities caption_entities
|
|
166
|
-
audio document photo sticker video voice
|
|
167
|
-
video_note contact location venue
|
|
168
|
-
new_chat_members left_chat_member
|
|
169
|
-
new_chat_title new_chat_photo
|
|
170
|
-
delete_chat_photo group_chat_created
|
|
171
|
-
supergroup_chat_created channel_chat_created
|
|
172
|
-
migrate_to_chat_id migrate_from_chat_id
|
|
173
|
-
pinned_message invoice successful_payment
|
|
174
|
-
connected_website reply_markup via_bot
|
|
175
|
-
forward_from forward_from_chat
|
|
176
|
-
forward_from_message_id forward_signature
|
|
177
|
-
forward_sender_name forward_date reply_to_message
|
|
178
|
-
media_group_id author_signature
|
|
179
|
-
has_protected_content].freeze
|
|
180
|
-
|
|
179
|
+
COMMON_FIELDS = %w[message_id from chat date edit_date
|
|
180
|
+
text caption entities caption_entities
|
|
181
|
+
audio document photo sticker video voice
|
|
182
|
+
video_note contact location venue
|
|
183
|
+
new_chat_members left_chat_member
|
|
184
|
+
new_chat_title new_chat_photo
|
|
185
|
+
delete_chat_photo group_chat_created
|
|
186
|
+
supergroup_chat_created channel_chat_created
|
|
187
|
+
migrate_to_chat_id migrate_from_chat_id
|
|
188
|
+
pinned_message invoice successful_payment
|
|
189
|
+
connected_website reply_markup via_bot
|
|
190
|
+
forward_from forward_from_chat
|
|
191
|
+
forward_from_message_id forward_signature
|
|
192
|
+
forward_sender_name forward_date reply_to_message
|
|
193
|
+
media_group_id author_signature
|
|
194
|
+
has_protected_content managed_bot_created managed_bot].freeze
|
|
195
|
+
|
|
181
196
|
def initialize(data)
|
|
182
197
|
super(data)
|
|
183
|
-
|
|
198
|
+
|
|
184
199
|
COMMON_FIELDS.each do |field|
|
|
185
200
|
define_accessor(field.to_sym)
|
|
186
201
|
end
|
|
187
|
-
|
|
202
|
+
|
|
188
203
|
convert_complex_fields
|
|
189
204
|
end
|
|
190
|
-
|
|
205
|
+
|
|
191
206
|
def command?
|
|
192
207
|
return false unless text && entities
|
|
193
|
-
|
|
194
|
-
entities.any? { |e| e.type == 'bot_command' &&
|
|
208
|
+
|
|
209
|
+
entities.any? { |e| e.type == 'bot_command' &&
|
|
195
210
|
text[e.offset, e.length]&.start_with?('/') }
|
|
196
211
|
end
|
|
197
|
-
|
|
212
|
+
|
|
198
213
|
def command_name
|
|
199
214
|
return nil unless command?
|
|
200
|
-
|
|
215
|
+
|
|
201
216
|
command_entity = entities.find { |e| e.type == 'bot_command' }
|
|
202
217
|
return nil unless command_entity
|
|
203
|
-
|
|
218
|
+
|
|
204
219
|
cmd = text[command_entity.offset, command_entity.length]
|
|
205
220
|
return nil if cmd.nil? || cmd.length <= 1
|
|
206
|
-
|
|
221
|
+
|
|
207
222
|
cmd = cmd[1..-1]
|
|
208
223
|
cmd.split('@').first.strip
|
|
209
224
|
end
|
|
210
|
-
|
|
225
|
+
|
|
211
226
|
def command_args
|
|
212
227
|
return nil unless command?
|
|
213
|
-
|
|
228
|
+
|
|
214
229
|
command_entity = entities.find { |e| e.type == 'bot_command' }
|
|
215
230
|
return nil unless command_entity
|
|
216
|
-
|
|
231
|
+
|
|
217
232
|
args_start = command_entity.offset + command_entity.length
|
|
218
233
|
remaining = text[args_start..-1]
|
|
219
|
-
|
|
234
|
+
|
|
220
235
|
next_entity = entities.select { |e| e.offset >= args_start }
|
|
221
236
|
.min_by(&:offset)
|
|
222
|
-
|
|
237
|
+
|
|
223
238
|
if next_entity
|
|
224
239
|
args_end = next_entity.offset - 1
|
|
225
240
|
text[args_start..args_end]&.strip
|
|
@@ -227,15 +242,15 @@ module Telegem
|
|
|
227
242
|
remaining&.strip
|
|
228
243
|
end
|
|
229
244
|
end
|
|
230
|
-
|
|
245
|
+
|
|
231
246
|
def reply?
|
|
232
247
|
!!reply_to_message
|
|
233
248
|
end
|
|
234
|
-
|
|
249
|
+
|
|
235
250
|
def has_media?
|
|
236
251
|
!!(audio || document || photo || video || voice || video_note || sticker)
|
|
237
252
|
end
|
|
238
|
-
|
|
253
|
+
|
|
239
254
|
def media_type
|
|
240
255
|
return :audio if audio
|
|
241
256
|
return :document if document
|
|
@@ -246,142 +261,166 @@ module Telegem
|
|
|
246
261
|
return :sticker if sticker
|
|
247
262
|
nil
|
|
248
263
|
end
|
|
249
|
-
|
|
264
|
+
|
|
250
265
|
private
|
|
251
|
-
|
|
266
|
+
|
|
252
267
|
def convert_complex_fields
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
268
|
+
# time conversions
|
|
269
|
+
@_raw_data['date'] = Time.at(@_raw_data['date']) if @_raw_data['date'] && !@_raw_data['date'].is_a?(Time)
|
|
270
|
+
@_raw_data['edit_date'] = Time.at(@_raw_data['edit_date']) if @_raw_data['edit_date'] && !@_raw_data['edit_date'].is_a?(Time)
|
|
271
|
+
@_raw_data['forward_date'] = Time.at(@_raw_data['forward_date']) if @_raw_data['forward_date'] && !@_raw_data['forward_date'].is_a?(Time)
|
|
272
|
+
|
|
273
|
+
# basic object wrappers
|
|
274
|
+
wrap('from', User)
|
|
275
|
+
wrap('chat', Chat)
|
|
276
|
+
wrap('via_bot', User)
|
|
277
|
+
wrap('forward_from', User)
|
|
278
|
+
wrap('forward_from_chat', Chat)
|
|
279
|
+
wrap('left_chat_member', User)
|
|
280
|
+
|
|
281
|
+
wrap_array('entities', MessageEntity)
|
|
282
|
+
wrap_array('caption_entities', MessageEntity)
|
|
283
|
+
|
|
284
|
+
wrap('reply_to_message', Message)
|
|
285
|
+
wrap('pinned_message', Message)
|
|
286
|
+
wrap_array('new_chat_members', User)
|
|
287
|
+
|
|
288
|
+
# media and other nested types
|
|
289
|
+
wrap('contact', Contact)
|
|
290
|
+
wrap('location', Location)
|
|
291
|
+
wrap('venue', Venue)
|
|
292
|
+
wrap('dice', Dice)
|
|
293
|
+
wrap('poll', Poll)
|
|
294
|
+
wrap('proximity_alert_triggered', ProximityAlertTriggered)
|
|
295
|
+
wrap('web_app_data', WebAppData)
|
|
296
|
+
|
|
297
|
+
wrap('animation', Animation)
|
|
298
|
+
wrap('audio', Audio)
|
|
299
|
+
wrap('document', Document)
|
|
300
|
+
wrap('video', Video)
|
|
301
|
+
wrap('voice', Voice)
|
|
302
|
+
wrap('video_note', VideoNote)
|
|
303
|
+
wrap('sticker', Sticker)
|
|
304
|
+
|
|
305
|
+
wrap('invoice', Invoice)
|
|
306
|
+
wrap('successful_payment', SuccessfulPayment)
|
|
307
|
+
wrap('reply_markup', BaseType)
|
|
308
|
+
|
|
309
|
+
wrap('passport_data', PassportData)
|
|
310
|
+
|
|
311
|
+
wrap('video_chat_scheduled', VideoChatScheduled)
|
|
312
|
+
wrap('video_chat_started', VideoChatStarted)
|
|
313
|
+
wrap('video_chat_ended', VideoChatEnded)
|
|
314
|
+
wrap('video_chat_participants_invited', VideoChatParticipantsInvited)
|
|
315
|
+
wrap('video_chat_location', VideoChatLocation)
|
|
316
|
+
|
|
317
|
+
# new message event objects introduced in later API versions
|
|
318
|
+
wrap('message_auto_delete_timer_changed', MessageAutoDeleteTimerChanged)
|
|
319
|
+
wrap('forum_topic_created', ForumTopicCreated)
|
|
320
|
+
wrap('forum_topic_edited', ForumTopicEdited)
|
|
321
|
+
wrap('forum_topic_closed', ForumTopicClosed)
|
|
322
|
+
wrap('forum_topic_reopened', ForumTopicReopened)
|
|
323
|
+
wrap('general_forum_topic_hidden', GeneralForumTopicHidden)
|
|
324
|
+
wrap('general_forum_topic_unhidden', GeneralForumTopicUnhidden)
|
|
325
|
+
wrap('write_access_allowed', WriteAccessAllowed)
|
|
326
|
+
|
|
327
|
+
# Bot API 9.6 - Managed Bot Support
|
|
328
|
+
wrap('managed_bot_created', ManagedBotCreated)
|
|
329
|
+
wrap('managed_bot', ManagedBotUpdated)
|
|
330
|
+
|
|
331
|
+
# arrays of sizes and photos
|
|
332
|
+
wrap_array('photo', PhotoSize)
|
|
333
|
+
wrap_array('new_chat_photo', PhotoSize)
|
|
334
|
+
|
|
335
|
+
# fall back to original media wrapper for backward compatibility
|
|
298
336
|
wrap_media_objects
|
|
299
337
|
end
|
|
300
|
-
|
|
338
|
+
|
|
301
339
|
def wrap_media_objects
|
|
302
|
-
# Media files
|
|
303
|
-
@_raw_data['document'] =
|
|
304
|
-
@_raw_data['
|
|
305
|
-
@_raw_data['
|
|
306
|
-
@_raw_data['
|
|
307
|
-
@_raw_data['
|
|
308
|
-
@_raw_data['
|
|
309
|
-
|
|
340
|
+
# Media files (fall‑back to generic types if no specific class defined)
|
|
341
|
+
@_raw_data['document'] = Document.new(@_raw_data['document']) if @_raw_data['document'] && !@_raw_data['document'].is_a?(Document)
|
|
342
|
+
@_raw_data['animation'] = Animation.new(@_raw_data['animation']) if @_raw_data['animation'] && !@_raw_data['animation'].is_a?(Animation)
|
|
343
|
+
@_raw_data['audio'] = Audio.new(@_raw_data['audio']) if @_raw_data['audio'] && !@_raw_data['audio'].is_a?(Audio)
|
|
344
|
+
@_raw_data['video'] = Video.new(@_raw_data['video']) if @_raw_data['video'] && !@_raw_data['video'].is_a?(Video)
|
|
345
|
+
@_raw_data['voice'] = Voice.new(@_raw_data['voice']) if @_raw_data['voice'] && !@_raw_data['voice'].is_a?(Voice)
|
|
346
|
+
@_raw_data['video_note'] = VideoNote.new(@_raw_data['video_note']) if @_raw_data['video_note'] && !@_raw_data['video_note'].is_a?(VideoNote)
|
|
347
|
+
@_raw_data['sticker'] = Sticker.new(@_raw_data['sticker']) if @_raw_data['sticker'] && !@_raw_data['sticker'].is_a?(Sticker)
|
|
348
|
+
|
|
310
349
|
# Photo array
|
|
311
350
|
if @_raw_data['photo'] && @_raw_data['photo'].is_a?(Array)
|
|
312
351
|
@_raw_data['photo'] = @_raw_data['photo'].map do |p|
|
|
313
|
-
p.is_a?(
|
|
352
|
+
p.is_a?(PhotoSize) ? p : PhotoSize.new(p)
|
|
314
353
|
end
|
|
315
354
|
end
|
|
316
|
-
|
|
355
|
+
|
|
317
356
|
# Contact, location, venue
|
|
318
|
-
@_raw_data['contact'] =
|
|
319
|
-
@_raw_data['location'] =
|
|
320
|
-
@_raw_data['venue'] =
|
|
321
|
-
|
|
357
|
+
@_raw_data['contact'] = Contact.new(@_raw_data['contact']) if @_raw_data['contact'] && !@_raw_data['contact'].is_a?(Contact)
|
|
358
|
+
@_raw_data['location'] = Location.new(@_raw_data['location']) if @_raw_data['location'] && !@_raw_data['location'].is_a?(Location)
|
|
359
|
+
@_raw_data['venue'] = Venue.new(@_raw_data['venue']) if @_raw_data['venue'] && !@_raw_data['venue'].is_a?(Venue)
|
|
360
|
+
|
|
322
361
|
# Payment & other
|
|
323
|
-
@_raw_data['invoice'] =
|
|
324
|
-
@_raw_data['successful_payment'] =
|
|
362
|
+
@_raw_data['invoice'] = Invoice.new(@_raw_data['invoice']) if @_raw_data['invoice'] && !@_raw_data['invoice'].is_a?(Invoice)
|
|
363
|
+
@_raw_data['successful_payment'] = SuccessfulPayment.new(@_raw_data['successful_payment']) if @_raw_data['successful_payment'] && !@_raw_data['successful_payment'].is_a?(SuccessfulPayment)
|
|
325
364
|
@_raw_data['reply_markup'] = BaseType.new(@_raw_data['reply_markup']) if @_raw_data['reply_markup'] && !@_raw_data['reply_markup'].is_a?(BaseType)
|
|
326
|
-
|
|
365
|
+
|
|
327
366
|
# Chat photo array
|
|
328
367
|
if @_raw_data['new_chat_photo'] && @_raw_data['new_chat_photo'].is_a?(Array)
|
|
329
368
|
@_raw_data['new_chat_photo'] = @_raw_data['new_chat_photo'].map do |p|
|
|
330
|
-
p.is_a?(
|
|
369
|
+
p.is_a?(PhotoSize) ? p : PhotoSize.new(p)
|
|
331
370
|
end
|
|
332
371
|
end
|
|
333
372
|
end
|
|
334
373
|
end
|
|
335
|
-
|
|
374
|
+
|
|
336
375
|
class CallbackQuery < BaseType
|
|
337
376
|
COMMON_FIELDS = %w[id from message inline_message_id chat_instance data game_short_name].freeze
|
|
338
|
-
|
|
377
|
+
|
|
339
378
|
def initialize(data)
|
|
340
379
|
super(data)
|
|
341
|
-
|
|
380
|
+
|
|
342
381
|
COMMON_FIELDS.each do |field|
|
|
343
382
|
define_accessor(field.to_sym)
|
|
344
383
|
end
|
|
345
|
-
|
|
384
|
+
|
|
346
385
|
if @_raw_data['from'] && !@_raw_data['from'].is_a?(User)
|
|
347
386
|
@_raw_data['from'] = User.new(@_raw_data['from'])
|
|
348
387
|
end
|
|
349
|
-
|
|
388
|
+
|
|
350
389
|
if @_raw_data['message'] && !@_raw_data['message'].is_a?(Message)
|
|
351
390
|
@_raw_data['message'] = Message.new(@_raw_data['message'])
|
|
352
391
|
end
|
|
353
392
|
end
|
|
354
|
-
|
|
393
|
+
|
|
355
394
|
def from_user?
|
|
356
395
|
!!from
|
|
357
396
|
end
|
|
358
|
-
|
|
397
|
+
|
|
359
398
|
def message?
|
|
360
399
|
!!message
|
|
361
400
|
end
|
|
362
|
-
|
|
401
|
+
|
|
363
402
|
def inline_message?
|
|
364
403
|
!!inline_message_id
|
|
365
404
|
end
|
|
366
405
|
end
|
|
367
|
-
|
|
406
|
+
|
|
368
407
|
class Update < BaseType
|
|
369
|
-
COMMON_FIELDS = %w[update_id message edited_message channel_post
|
|
370
|
-
edited_channel_post inline_query chosen_inline_result
|
|
371
|
-
callback_query shipping_query pre_checkout_query
|
|
372
|
-
poll poll_answer my_chat_member chat_member
|
|
373
|
-
chat_join_request].freeze
|
|
374
|
-
|
|
408
|
+
COMMON_FIELDS = %w[update_id message edited_message channel_post
|
|
409
|
+
edited_channel_post inline_query chosen_inline_result
|
|
410
|
+
callback_query shipping_query pre_checkout_query
|
|
411
|
+
poll poll_answer my_chat_member chat_member
|
|
412
|
+
chat_join_request managed_bot_created managed_bot].freeze
|
|
413
|
+
|
|
375
414
|
def initialize(data)
|
|
376
415
|
super(data)
|
|
377
|
-
|
|
416
|
+
|
|
378
417
|
COMMON_FIELDS.each do |field|
|
|
379
418
|
define_accessor(field.to_sym)
|
|
380
419
|
end
|
|
381
|
-
|
|
420
|
+
|
|
382
421
|
convert_update_objects
|
|
383
422
|
end
|
|
384
|
-
|
|
423
|
+
|
|
385
424
|
def type
|
|
386
425
|
return :message if message
|
|
387
426
|
return :edited_message if edited_message
|
|
@@ -397,9 +436,11 @@ module Telegem
|
|
|
397
436
|
return :my_chat_member if my_chat_member
|
|
398
437
|
return :chat_member if chat_member
|
|
399
438
|
return :chat_join_request if chat_join_request
|
|
439
|
+
return :managed_bot_created if managed_bot_created
|
|
440
|
+
return :managed_bot if managed_bot
|
|
400
441
|
:unknown
|
|
401
442
|
end
|
|
402
|
-
|
|
443
|
+
|
|
403
444
|
def from
|
|
404
445
|
case type
|
|
405
446
|
when :message, :edited_message
|
|
@@ -420,23 +461,243 @@ module Telegem
|
|
|
420
461
|
my_chat_member&.from || chat_member&.from
|
|
421
462
|
when :chat_join_request
|
|
422
463
|
chat_join_request.from
|
|
464
|
+
when :managed_bot_created, :managed_bot
|
|
465
|
+
managed_bot_created&.from || managed_bot&.from
|
|
423
466
|
else
|
|
424
467
|
nil
|
|
425
468
|
end
|
|
426
469
|
end
|
|
427
|
-
|
|
470
|
+
|
|
428
471
|
private
|
|
429
|
-
|
|
472
|
+
|
|
430
473
|
def convert_update_objects
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
474
|
+
wrap('message', Message)
|
|
475
|
+
wrap('edited_message', Message)
|
|
476
|
+
wrap('channel_post', Message)
|
|
477
|
+
wrap('edited_channel_post', Message)
|
|
478
|
+
|
|
479
|
+
wrap('inline_query', InlineQuery)
|
|
480
|
+
wrap('chosen_inline_result', ChosenInlineResult)
|
|
481
|
+
wrap('callback_query', CallbackQuery)
|
|
482
|
+
wrap('shipping_query', ShippingQuery)
|
|
483
|
+
wrap('pre_checkout_query', PreCheckoutQuery)
|
|
484
|
+
wrap('poll', Poll)
|
|
485
|
+
wrap('poll_answer', PollAnswer)
|
|
486
|
+
wrap('my_chat_member', ChatMemberUpdated)
|
|
487
|
+
wrap('chat_member', ChatMemberUpdated)
|
|
488
|
+
wrap('chat_join_request', ChatJoinRequest)
|
|
489
|
+
wrap('forum_topic_created', ForumTopicCreated)
|
|
490
|
+
wrap('forum_topic_edited', ForumTopicEdited)
|
|
491
|
+
wrap('forum_topic_closed', ForumTopicClosed)
|
|
492
|
+
wrap('forum_topic_reopened', ForumTopicReopened)
|
|
493
|
+
wrap('general_forum_topic_hidden', GeneralForumTopicHidden)
|
|
494
|
+
wrap('general_forum_topic_unhidden', GeneralForumTopicUnhidden)
|
|
495
|
+
wrap('write_access_allowed', WriteAccessAllowed)
|
|
496
|
+
|
|
497
|
+
# Bot API 9.6 - Managed Bot Support
|
|
498
|
+
wrap('managed_bot_created', ManagedBotCreated)
|
|
499
|
+
wrap('managed_bot', ManagedBotUpdated)
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
# additional types returned by various methods / updates
|
|
504
|
+
class PhotoSize < BaseType; end
|
|
505
|
+
class Audio < BaseType; end
|
|
506
|
+
class Document < BaseType; end
|
|
507
|
+
class Video < BaseType; end
|
|
508
|
+
class Voice < BaseType; end
|
|
509
|
+
class VideoNote < BaseType; end
|
|
510
|
+
class Animation < BaseType; end
|
|
511
|
+
class Sticker < BaseType; end
|
|
512
|
+
class Contact < BaseType; end
|
|
513
|
+
class Dice < BaseType; end
|
|
514
|
+
|
|
515
|
+
class Location < BaseType; end
|
|
516
|
+
class Venue < BaseType; end
|
|
517
|
+
class ProximityAlertTriggered < BaseType; end
|
|
518
|
+
class WebAppData < BaseType; end
|
|
519
|
+
class PassportData < BaseType; end
|
|
520
|
+
|
|
521
|
+
class Invoice < BaseType; end
|
|
522
|
+
class SuccessfulPayment < BaseType; end
|
|
523
|
+
class ShippingAddress < BaseType; end
|
|
524
|
+
class OrderInfo < BaseType; end
|
|
525
|
+
|
|
526
|
+
class ShippingQuery < BaseType
|
|
527
|
+
def initialize(data)
|
|
528
|
+
super(data)
|
|
529
|
+
wrap('from', User)
|
|
530
|
+
wrap('shipping_address', ShippingAddress)
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
class PreCheckoutQuery < BaseType
|
|
535
|
+
def initialize(data)
|
|
536
|
+
super(data)
|
|
537
|
+
wrap('from', User)
|
|
538
|
+
wrap('shipping_address', ShippingAddress)
|
|
539
|
+
wrap('order_info', OrderInfo)
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
class PollOption < BaseType
|
|
544
|
+
def initialize(data)
|
|
545
|
+
super(data)
|
|
546
|
+
# Bot API 9.6 enhancements
|
|
547
|
+
wrap('added_by_user', User)
|
|
548
|
+
wrap('added_by_chat', Chat)
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
class PollAnswer < BaseType; end
|
|
553
|
+
|
|
554
|
+
class Poll < BaseType
|
|
555
|
+
def initialize(data)
|
|
556
|
+
super(data)
|
|
557
|
+
wrap_array('options', PollOption)
|
|
558
|
+
wrap_array('explanation_entities', MessageEntity)
|
|
559
|
+
end
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
class ChatPermissions < BaseType; end
|
|
563
|
+
class ChatPhoto < BaseType; end
|
|
564
|
+
class ChatInviteLink < BaseType; end
|
|
565
|
+
|
|
566
|
+
# status-specific chat member objects. they inherit from ChatMember
|
|
567
|
+
class ChatMember < BaseType; end
|
|
568
|
+
class ChatMemberOwner < ChatMember; end
|
|
569
|
+
class ChatMemberAdministrator < ChatMember; end
|
|
570
|
+
class ChatMemberMember < ChatMember; end
|
|
571
|
+
class ChatMemberRestricted < ChatMember; end
|
|
572
|
+
class ChatMemberLeft < ChatMember; end
|
|
573
|
+
class ChatMemberBanned < ChatMember; end
|
|
574
|
+
|
|
575
|
+
class ChatAdministratorRights < BaseType; end
|
|
576
|
+
|
|
577
|
+
class ChatMemberUpdated < BaseType
|
|
578
|
+
def initialize(data)
|
|
579
|
+
super(data)
|
|
580
|
+
wrap('chat', Chat)
|
|
581
|
+
wrap('from', User)
|
|
582
|
+
wrap_member('old_chat_member')
|
|
583
|
+
wrap_member('new_chat_member')
|
|
584
|
+
wrap('invite_link', ChatInviteLink)
|
|
585
|
+
if @_raw_data['date'] && !@_raw_data['date'].is_a?(Time)
|
|
586
|
+
@_raw_data['date'] = Time.at(@_raw_data['date'])
|
|
438
587
|
end
|
|
439
588
|
end
|
|
589
|
+
|
|
590
|
+
private
|
|
591
|
+
|
|
592
|
+
def wrap_member(key)
|
|
593
|
+
return unless @_raw_data[key]
|
|
594
|
+
status = @_raw_data[key]['status']
|
|
595
|
+
klass = case status
|
|
596
|
+
when 'creator' then ChatMemberOwner
|
|
597
|
+
when 'administrator' then ChatMemberAdministrator
|
|
598
|
+
when 'member' then ChatMemberMember
|
|
599
|
+
when 'restricted' then ChatMemberRestricted
|
|
600
|
+
when 'left' then ChatMemberLeft
|
|
601
|
+
when 'kicked' then ChatMemberBanned
|
|
602
|
+
else ChatMember
|
|
603
|
+
end
|
|
604
|
+
@_raw_data[key] = klass.new(@_raw_data[key])
|
|
605
|
+
end
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
class ChatJoinRequest < BaseType
|
|
609
|
+
def initialize(data)
|
|
610
|
+
super(data)
|
|
611
|
+
wrap('chat', Chat)
|
|
612
|
+
wrap('from', User)
|
|
613
|
+
wrap('invite_link', ChatInviteLink)
|
|
614
|
+
if @_raw_data['date'] && !@_raw_data['date'].is_a?(Time)
|
|
615
|
+
@_raw_data['date'] = Time.at(@_raw_data['date'])
|
|
616
|
+
end
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
class InlineQuery < BaseType
|
|
621
|
+
def initialize(data)
|
|
622
|
+
super(data)
|
|
623
|
+
wrap('from', User)
|
|
624
|
+
wrap('location', Location)
|
|
625
|
+
end
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
class ChosenInlineResult < BaseType
|
|
629
|
+
def initialize(data)
|
|
630
|
+
super(data)
|
|
631
|
+
wrap('from', User)
|
|
632
|
+
wrap('location', Location)
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
class InlineQueryResult < BaseType; end
|
|
637
|
+
class InlineQueryResultArticle < InlineQueryResult; end
|
|
638
|
+
class InlineQueryResultPhoto < InlineQueryResult; end
|
|
639
|
+
class InlineQueryResultGif < InlineQueryResult; end
|
|
640
|
+
class InlineQueryResultMpeg4Gif < InlineQueryResult; end
|
|
641
|
+
class InlineQueryResultVideo < InlineQueryResult; end
|
|
642
|
+
class InlineQueryResultAudio < InlineQueryResult; end
|
|
643
|
+
class InlineQueryResultVoice < InlineQueryResult; end
|
|
644
|
+
class InlineQueryResultDocument < InlineQueryResult; end
|
|
645
|
+
class InlineQueryResultLocation < InlineQueryResult; end
|
|
646
|
+
class InlineQueryResultVenue < InlineQueryResult; end
|
|
647
|
+
class InlineQueryResultContact < InlineQueryResult; end
|
|
648
|
+
class InlineQueryResultGame < InlineQueryResult; end
|
|
649
|
+
class InlineQueryResultSticker < InlineQueryResult; end
|
|
650
|
+
class InlineQueryResultCachedPhoto < InlineQueryResult; end
|
|
651
|
+
class InlineQueryResultCachedGif < InlineQueryResult; end
|
|
652
|
+
class InlineQueryResultCachedMpeg4Gif < InlineQueryResult; end
|
|
653
|
+
class InlineQueryResultCachedSticker < InlineQueryResult; end
|
|
654
|
+
class InlineQueryResultCachedDocument < InlineQueryResult; end
|
|
655
|
+
class InlineQueryResultCachedVideo < InlineQueryResult; end
|
|
656
|
+
class InlineQueryResultCachedAudio < InlineQueryResult; end
|
|
657
|
+
class InlineQueryResultCachedVoice < InlineQueryResult; end
|
|
658
|
+
|
|
659
|
+
class UserProfilePhotos < BaseType
|
|
660
|
+
def initialize(data)
|
|
661
|
+
super(data)
|
|
662
|
+
wrap_array('photos', PhotoSize)
|
|
663
|
+
end
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
class UserProfileAudios < BaseType
|
|
667
|
+
def initialize(data)
|
|
668
|
+
super(data)
|
|
669
|
+
wrap_array('audios', Audio)
|
|
670
|
+
end
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
# generic utility objects returned by the API
|
|
674
|
+
class File < BaseType; end
|
|
675
|
+
class ResponseParameters < BaseType; end
|
|
676
|
+
class MaskPosition < BaseType; end
|
|
677
|
+
class StickerSet < BaseType; end
|
|
678
|
+
|
|
679
|
+
# new message event payloads (each a simple wrapper)
|
|
680
|
+
class MessageAutoDeleteTimerChanged < BaseType; end
|
|
681
|
+
class ForumTopicCreated < BaseType; end
|
|
682
|
+
class ForumTopicEdited < BaseType; end
|
|
683
|
+
class ForumTopicClosed < BaseType; end
|
|
684
|
+
class ForumTopicReopened < BaseType; end
|
|
685
|
+
class GeneralForumTopicHidden < BaseType; end
|
|
686
|
+
class GeneralForumTopicUnhidden < BaseType; end
|
|
687
|
+
class WriteAccessAllowed < BaseType; end
|
|
688
|
+
|
|
689
|
+
class BotCommand < BaseType; end
|
|
690
|
+
class BotCommandScope < BaseType; end
|
|
691
|
+
class WebhookInfo < BaseType; end
|
|
692
|
+
|
|
693
|
+
class VideoChatScheduled < BaseType; end
|
|
694
|
+
class VideoChatStarted < BaseType; end
|
|
695
|
+
class VideoChatEnded < BaseType; end
|
|
696
|
+
class VideoChatParticipantsInvited < BaseType; end
|
|
697
|
+
class VideoChatLocation < BaseType; end
|
|
698
|
+
# Bot API 9.6 - Managed Bot Support
|
|
699
|
+
class ManagedBotCreated < BaseType; end
|
|
700
|
+
class ManagedBotDeleted < BaseType; end
|
|
701
|
+
class ManagedBotUpdated < BaseType; end
|
|
440
702
|
end
|
|
441
703
|
end
|
|
442
|
-
end
|