bobot 1.0.52

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +66 -0
  4. data/Rakefile +19 -0
  5. data/app/controllers/bobot/application_controller.rb +5 -0
  6. data/app/controllers/bobot/webhook_controller.rb +76 -0
  7. data/app/jobs/bobot/application_job.rb +4 -0
  8. data/app/jobs/bobot/commander_job.rb +9 -0
  9. data/app/jobs/bobot/deliver_job.rb +16 -0
  10. data/app/mailers/bobot/application_mailer.rb +6 -0
  11. data/app/models/bobot/application_record.rb +5 -0
  12. data/config/locales/bobot.en.yml +28 -0
  13. data/config/routes.rb +6 -0
  14. data/lib/bobot.rb +18 -0
  15. data/lib/bobot/buttons.rb +168 -0
  16. data/lib/bobot/commander.rb +68 -0
  17. data/lib/bobot/configuration.rb +206 -0
  18. data/lib/bobot/engine.rb +33 -0
  19. data/lib/bobot/error_parser.rb +102 -0
  20. data/lib/bobot/event.rb +40 -0
  21. data/lib/bobot/events/account_linking.rb +15 -0
  22. data/lib/bobot/events/common.rb +170 -0
  23. data/lib/bobot/events/delivery.rb +20 -0
  24. data/lib/bobot/events/message.rb +72 -0
  25. data/lib/bobot/events/message_echo.rb +8 -0
  26. data/lib/bobot/events/optin.rb +11 -0
  27. data/lib/bobot/events/postback.rb +20 -0
  28. data/lib/bobot/events/read.rb +15 -0
  29. data/lib/bobot/events/referral.rb +33 -0
  30. data/lib/bobot/exceptions.rb +73 -0
  31. data/lib/bobot/graph_facebook.rb +90 -0
  32. data/lib/bobot/profile.rb +23 -0
  33. data/lib/bobot/subscription.rb +19 -0
  34. data/lib/bobot/user.rb +13 -0
  35. data/lib/bobot/version.rb +14 -0
  36. data/lib/generators/bobot/install_generator.rb +28 -0
  37. data/lib/generators/bobot/templates/app/bobot/message.rb +3 -0
  38. data/lib/generators/bobot/templates/app/bobot/postback.rb +22 -0
  39. data/lib/generators/bobot/templates/app/bobot/workflow.rb +17 -0
  40. data/lib/generators/bobot/templates/config/bobot.yml +39 -0
  41. data/lib/generators/bobot/templates/config/initializers/bobot.rb +30 -0
  42. data/lib/generators/bobot/templates/config/locales/bobot.en.yml +30 -0
  43. data/lib/generators/bobot/templates/config/locales/bobot.fr.yml +29 -0
  44. data/lib/generators/bobot/uninstall_generator.rb +24 -0
  45. data/lib/generators/bobot/utils.rb +30 -0
  46. data/lib/tasks/bobot_tasks.rake +11 -0
  47. data/spec/bobot/bobot_spec.rb +24 -0
  48. data/spec/bobot/event/account_linking_spec.rb +59 -0
  49. data/spec/bobot/event/common_spec.rb +259 -0
  50. data/spec/bobot/event/delivery_spec.rb +62 -0
  51. data/spec/bobot/event/message_echo_spec.rb +276 -0
  52. data/spec/bobot/event/message_spec.rb +276 -0
  53. data/spec/bobot/event/optin_spec.rb +50 -0
  54. data/spec/bobot/event/postback_spec.rb +94 -0
  55. data/spec/bobot/event/read_spec.rb +51 -0
  56. data/spec/bobot/event/referral_spec.rb +66 -0
  57. data/spec/bobot/event_spec.rb +167 -0
  58. data/spec/bobot/install_generator_spec.rb +43 -0
  59. data/spec/bobot/profile_spec.rb +170 -0
  60. data/spec/bobot/subscription_spec.rb +139 -0
  61. data/spec/bobot/user_spec.rb +91 -0
  62. data/spec/controllers/bobot/application_controller_spec.rb +4 -0
  63. data/spec/controllers/bobot/webhook_controller_spec.rb +5 -0
  64. data/spec/dummy/Rakefile +6 -0
  65. data/spec/dummy/app/assets/config/manifest.js +3 -0
  66. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  67. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  68. data/spec/dummy/app/bobot/workflow.rb +17 -0
  69. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  70. data/spec/dummy/app/jobs/application_job.rb +2 -0
  71. data/spec/dummy/app/models/application_record.rb +3 -0
  72. data/spec/dummy/bin/bundle +3 -0
  73. data/spec/dummy/bin/rails +4 -0
  74. data/spec/dummy/bin/rake +4 -0
  75. data/spec/dummy/bin/setup +35 -0
  76. data/spec/dummy/bin/update +29 -0
  77. data/spec/dummy/config.ru +5 -0
  78. data/spec/dummy/config/application.rb +30 -0
  79. data/spec/dummy/config/bobot.yml +27 -0
  80. data/spec/dummy/config/boot.rb +5 -0
  81. data/spec/dummy/config/database.yml +19 -0
  82. data/spec/dummy/config/environment.rb +5 -0
  83. data/spec/dummy/config/environments/development.rb +42 -0
  84. data/spec/dummy/config/environments/production.rb +78 -0
  85. data/spec/dummy/config/environments/test.rb +38 -0
  86. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  87. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  88. data/spec/dummy/config/initializers/bobot.rb +30 -0
  89. data/spec/dummy/config/initializers/cors.rb +16 -0
  90. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  91. data/spec/dummy/config/initializers/inflections.rb +16 -0
  92. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  93. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  94. data/spec/dummy/config/locales/bobot.en.yml +28 -0
  95. data/spec/dummy/config/locales/bobot.fr.yml +27 -0
  96. data/spec/dummy/config/locales/en.yml +33 -0
  97. data/spec/dummy/config/puma.rb +56 -0
  98. data/spec/dummy/config/routes.rb +3 -0
  99. data/spec/dummy/config/secrets.yml +32 -0
  100. data/spec/dummy/config/spring.rb +6 -0
  101. data/spec/dummy/db/schema.rb +15 -0
  102. data/spec/examples.txt +111 -0
  103. data/spec/helpers/graph_api_helpers.rb +6 -0
  104. data/spec/jobs/bobot/commander_job_spec.rb +31 -0
  105. data/spec/lint/rubocop_spec.rb +8 -0
  106. data/spec/rails_helper.rb +67 -0
  107. data/spec/spec_helper.rb +105 -0
  108. data/spec/travis/database.travis.mysql.yml +19 -0
  109. metadata +251 -0
@@ -0,0 +1,24 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Bobot do
4
+ describe '#configure' do
5
+ it 'sets correct configuration' do
6
+ Bobot.configure do |config|
7
+ config.app_id = '1'
8
+ config.app_secret = '2'
9
+ config.page_access_token = '3'
10
+ config.verify_token = '4'
11
+ config.page_id = '5'
12
+ config.debug_log = true
13
+ config.async = true
14
+ end
15
+ expect(Bobot.app_id).to eql('1')
16
+ expect(Bobot.app_secret).to eql('2')
17
+ expect(Bobot.page_access_token).to eql('3')
18
+ expect(Bobot.verify_token).to eql('4')
19
+ expect(Bobot.page_id).to eql('5')
20
+ expect(Bobot.debug_log).to eql(true)
21
+ expect(Bobot.async).to eql(true)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,59 @@
1
+ require 'rails_helper'
2
+ require 'helpers/graph_api_helpers'
3
+
4
+ RSpec.describe Bobot::Event::AccountLinking do
5
+ let :payload do
6
+ {
7
+ 'sender' => {
8
+ 'id' => '3'
9
+ },
10
+ 'recipient' => {
11
+ 'id' => '3'
12
+ },
13
+ 'timestamp' => 145_776_419_762_7,
14
+ 'account_linking' => {
15
+ 'status' => 'linked',
16
+ 'authorization_code' => 'PASS_THROUGH_AUTHORIZATION_CODE'
17
+ }
18
+ }
19
+ end
20
+
21
+ subject { Bobot::Event::AccountLinking.new(payload) }
22
+
23
+ describe '.messaging' do
24
+ it 'returns the original payload' do
25
+ expect(subject.messaging).to eq(payload)
26
+ end
27
+ end
28
+
29
+ describe '.sender' do
30
+ it 'returns the sender' do
31
+ expect(subject.sender).to eq(payload['sender'])
32
+ end
33
+ end
34
+
35
+ describe '.recipient' do
36
+ it 'returns the recipient' do
37
+ expect(subject.recipient).to eq(payload['recipient'])
38
+ end
39
+ end
40
+
41
+ describe '.sent_at' do
42
+ it 'returns when the postback was sent' do
43
+ expect(subject.sent_at).to eq(Time.zone.at(payload['timestamp'] / 1000))
44
+ end
45
+ end
46
+
47
+ describe '.status' do
48
+ it 'returns linking status defined with the entry point' do
49
+ expect(subject.status).to eq(payload['account_linking']['status'])
50
+ end
51
+ end
52
+
53
+ describe '.authorization_code' do
54
+ it 'returns authorization code defined with the entry point' do
55
+ expect(subject.authorization_code)
56
+ .to eq(payload['account_linking']['authorization_code'])
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,259 @@
1
+ require 'rails_helper'
2
+
3
+ module Bobot
4
+ class Dummy
5
+ include Bobot::Event::Common
6
+ end
7
+ end
8
+
9
+ RSpec.describe Bobot::Dummy do
10
+ let :payload do
11
+ {
12
+ 'sender' => {
13
+ 'id' => '3'
14
+ },
15
+ 'recipient' => {
16
+ 'id' => '3'
17
+ },
18
+ 'timestamp' => 145_776_419_762_7,
19
+ 'message' => {
20
+ 'is_echo' => false,
21
+ 'mid' => 'mid.1457764197618:41d102a3e1ae206a38',
22
+ 'seq' => 73,
23
+ 'text' => 'Hello, bot!',
24
+ 'quick_reply' => {
25
+ 'payload' => 'Hi, I am a quick reply!'
26
+ },
27
+ 'attachments' => [{
28
+ 'type' => 'image',
29
+ 'payload' => {
30
+ 'url' => 'https://www.example.com/1.jpg'
31
+ }
32
+ }]
33
+ }
34
+ }
35
+ end
36
+
37
+ let(:access_token) { 'access_token' }
38
+
39
+ before do
40
+ Bobot.page_access_token = access_token
41
+ end
42
+
43
+ subject { described_class.new(payload) }
44
+
45
+ describe '.sender' do
46
+ it 'returns the sender' do
47
+ expect(subject.sender).to eq(payload['sender'])
48
+ end
49
+ end
50
+
51
+ describe '.recipient' do
52
+ it 'returns the recipient' do
53
+ expect(subject.recipient).to eq(payload['recipient'])
54
+ end
55
+ end
56
+
57
+ describe '.sent_at' do
58
+ it 'returns when the message was sent' do
59
+ expect(subject.sent_at).to eq(Time.zone.at(payload['timestamp'] / 1000))
60
+ end
61
+ end
62
+
63
+ describe '.show_typing' do
64
+ it 'sends a typing on indicator to the sender' do
65
+ expect(subject).to receive(:deliver).with(
66
+ payload_template: { sender_action: 'typing_on' }
67
+ )
68
+ subject.show_typing(state: true)
69
+ end
70
+ it 'sends a typing on indicator to the sender' do
71
+ expect(subject).to receive(:deliver).with(
72
+ payload_template: { sender_action: 'typing_off' }
73
+ )
74
+ subject.show_typing(state: false)
75
+ end
76
+ end
77
+
78
+ describe '.mark_as_seen' do
79
+ it 'sends a typing off indicator to the sender' do
80
+ expect(subject).to receive(:deliver).with(
81
+ payload_template: { sender_action: 'mark_seen' }
82
+ )
83
+ subject.mark_as_seen
84
+ end
85
+ end
86
+
87
+ describe '.reply_with_text' do
88
+ it 'replies to the sender' do
89
+ expect(subject).to receive(:deliver).with(
90
+ payload_template: { message: { text: 'Hello, human' } }
91
+ )
92
+ subject.reply_with_text(text: 'Hello, human')
93
+ end
94
+ end
95
+
96
+ describe '.reply_with_image' do
97
+ it 'replies to the sender' do
98
+ expect(subject).to receive(:deliver).with(
99
+ payload_template: {
100
+ message: {
101
+ attachment: {
102
+ type: 'image',
103
+ payload: {
104
+ url: 'https://www.foo.bar/image.jpg',
105
+ is_reusable: true,
106
+ },
107
+ },
108
+ },
109
+ },
110
+ )
111
+ subject.reply_with_image(url: 'https://www.foo.bar/image.jpg')
112
+ end
113
+ end
114
+
115
+ describe '.reply_with_audio' do
116
+ it 'replies to the sender' do
117
+ expect(subject).to receive(:deliver).with(
118
+ payload_template: {
119
+ message: {
120
+ attachment: {
121
+ type: 'audio',
122
+ payload: {
123
+ url: 'https://www.foo.bar/audio.mp3',
124
+ },
125
+ },
126
+ },
127
+ },
128
+ )
129
+ subject.reply_with_audio(url: 'https://www.foo.bar/audio.mp3')
130
+ end
131
+ end
132
+
133
+ describe '.reply_with_video' do
134
+ it 'replies to the sender' do
135
+ expect(subject).to receive(:deliver).with(
136
+ payload_template: {
137
+ message: {
138
+ attachment: {
139
+ type: 'video',
140
+ payload: {
141
+ url: 'https://www.foo.bar/video.mp4',
142
+ },
143
+ },
144
+ },
145
+ },
146
+ )
147
+ subject.reply_with_video(url: 'https://www.foo.bar/video.mp4')
148
+ end
149
+ end
150
+
151
+ describe '.reply_with_file' do
152
+ it 'replies to the sender' do
153
+ expect(subject).to receive(:deliver).with(
154
+ payload_template: {
155
+ message: {
156
+ attachment: {
157
+ type: 'file',
158
+ payload: {
159
+ url: 'https://www.foo.bar/file.zip',
160
+ },
161
+ },
162
+ },
163
+ },
164
+ )
165
+ subject.reply_with_file(url: 'https://www.foo.bar/file.zip')
166
+ end
167
+ end
168
+
169
+ describe '.reply_with_quick_replies' do
170
+ it 'replies to the sender' do
171
+ expect(subject).to receive(:deliver).with(
172
+ payload_template: {
173
+ message: {
174
+ text: 'Pick a color:',
175
+ quick_replies: [
176
+ {
177
+ content_type: 'text',
178
+ title: 'RED',
179
+ payload: 'PICKED_RED_COLOR',
180
+ image_url: 'https://foo.bar/red.png'
181
+ },
182
+ {
183
+ content_type: 'text',
184
+ title: 'GREEN',
185
+ payload: 'PICKED_GREEN_COLOR'
186
+ }
187
+ ]
188
+ },
189
+ },
190
+ )
191
+ subject.reply_with_quick_replies(
192
+ text: 'Pick a color:',
193
+ quick_replies: [
194
+ {
195
+ content_type: 'text',
196
+ title: 'RED',
197
+ payload: 'PICKED_RED_COLOR',
198
+ image_url: 'https://foo.bar/red.png'
199
+ },
200
+ {
201
+ content_type: 'text',
202
+ title: 'GREEN',
203
+ payload: 'PICKED_GREEN_COLOR'
204
+ },
205
+ ]
206
+ )
207
+ end
208
+ it 'asks the location to the sender' do
209
+ expect(subject).to receive(:deliver).with(
210
+ payload_template: {
211
+ message: {
212
+ text: 'Where are you',
213
+ quick_replies: [
214
+ {
215
+ content_type: 'location',
216
+ image_url: 'https://foo.bar/gps.png',
217
+ }
218
+ ]
219
+ },
220
+ },
221
+ )
222
+ subject.reply_with_quick_replies(
223
+ text: 'Where are you',
224
+ quick_replies: [
225
+ Bobot::Buttons.quick_reply_location(image_url: 'https://foo.bar/gps.png')
226
+ ]
227
+ )
228
+ end
229
+ end
230
+
231
+ describe '.reply_with_buttons' do
232
+ it 'replies to the sender' do
233
+ expect(subject).to receive(:deliver).with(
234
+ payload_template: {
235
+ message: {
236
+ attachment: {
237
+ type: 'template',
238
+ payload: {
239
+ template_type: 'button',
240
+ text: 'Human, do you like me?',
241
+ buttons: [
242
+ { type: 'postback', title: 'Yes', payload: 'HARMLESS' },
243
+ { type: 'postback', title: 'No', payload: 'WHAT_IS_A_CHATBOT' }
244
+ ]
245
+ }
246
+ }
247
+ },
248
+ },
249
+ )
250
+ subject.reply_with_buttons(
251
+ text: 'Human, do you like me?',
252
+ buttons: [
253
+ { type: 'postback', title: 'Yes', payload: 'HARMLESS' },
254
+ { type: 'postback', title: 'No', payload: 'WHAT_IS_A_CHATBOT' }
255
+ ]
256
+ )
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,62 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Bobot::Event::Delivery do
4
+ let :payload do
5
+ {
6
+ 'sender' => {
7
+ 'id' => '3'
8
+ },
9
+ 'recipient' => {
10
+ 'id' => '3'
11
+ },
12
+ 'delivery' => {
13
+ 'mids' => [
14
+ 'mid.1457764197618:41d102a3e1ae206a38',
15
+ 'mid.1458668856218:ed81099e15d3f4f233'
16
+ ],
17
+ 'watermark' => 145_866_885_625_3,
18
+ 'seq' => 37
19
+ }
20
+ }
21
+ end
22
+
23
+ subject { Bobot::Event::Delivery.new(payload) }
24
+
25
+ describe '.messaging' do
26
+ it 'returns the original payload' do
27
+ expect(subject.messaging).to eq(payload)
28
+ end
29
+ end
30
+
31
+ describe '.ids' do
32
+ it 'returns the message ids' do
33
+ expect(subject.ids).to eq(payload['delivery']['mids'])
34
+ end
35
+ end
36
+
37
+ describe '.sender' do
38
+ it 'returns the sender' do
39
+ expect(subject.sender).to eq(payload['sender'])
40
+ end
41
+ end
42
+
43
+ describe '.recipient' do
44
+ it 'returns the recipient' do
45
+ expect(subject.recipient).to eq(payload['recipient'])
46
+ end
47
+ end
48
+
49
+ describe '.seq' do
50
+ it 'returns the message sequence number' do
51
+ expect(subject.seq).to eq(payload['delivery']['seq'])
52
+ end
53
+ end
54
+
55
+ describe '.at' do
56
+ it 'returns a Time' do
57
+ expect(subject.at).to eq(
58
+ Time.zone.at(payload['delivery']['watermark'] / 1000)
59
+ )
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,276 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Bobot::Event::MessageEcho do
4
+ let :payload do
5
+ {
6
+ 'sender' => {
7
+ 'id' => '3'
8
+ },
9
+ 'recipient' => {
10
+ 'id' => '3'
11
+ },
12
+ 'timestamp' => 145_776_419_762_7,
13
+ 'message' => {
14
+ 'is_echo' => true,
15
+ 'app_id' => 184_719_329_217_930_000,
16
+ 'mid' => 'mid.1457764197618:41d102a3e1ae206a38',
17
+ 'seq' => 73,
18
+ 'text' => 'Hello, bot!',
19
+ 'quick_reply' => {
20
+ 'payload' => 'Hi, I am a quick reply!'
21
+ },
22
+ 'attachments' => [{
23
+ 'type' => 'image',
24
+ 'payload' => {
25
+ 'url' => 'https://www.example.com/1.jpg'
26
+ }
27
+ }]
28
+ }
29
+ }
30
+ end
31
+
32
+ let :video_payload do
33
+ {
34
+ 'sender' => {
35
+ 'id' => '5'
36
+ },
37
+ 'recipient' => {
38
+ 'id' => '7'
39
+ },
40
+ 'timestamp' => 145_776_419_762_4,
41
+ 'message' => {
42
+ 'is_echo' => true,
43
+ 'app_id' => 184_719_329_217_930_001,
44
+ 'mid' => 'mid.1457764197618:41d102a3e1ae206a38',
45
+ 'attachments' => [{
46
+ 'type' => 'video',
47
+ 'payload' => {
48
+ 'url' => 'https://www.example.com/2.mp4'
49
+ }
50
+ }]
51
+ }
52
+ }
53
+ end
54
+
55
+ let :file_payload do
56
+ {
57
+ 'sender' => {
58
+ 'id' => '5'
59
+ },
60
+ 'recipient' => {
61
+ 'id' => '7'
62
+ },
63
+ 'timestamp' => 145_776_412_762_4,
64
+ 'message' => {
65
+ 'is_echo' => true,
66
+ 'app_id' => 184_719_329_217_930_001,
67
+ 'mid' => 'mid.1457764197618:41d102a3e1ae206a39',
68
+ 'attachments' => [{
69
+ 'type' => 'file',
70
+ 'payload' => {
71
+ 'url' => 'https://www.example.com/3.pdf'
72
+ }
73
+ }]
74
+ }
75
+ }
76
+ end
77
+
78
+ let :audio_payload do
79
+ {
80
+ 'sender' => {
81
+ 'id' => '8'
82
+ },
83
+ 'recipient' => {
84
+ 'id' => '9'
85
+ },
86
+ 'timestamp' => 145_776_419_732_4,
87
+ 'message' => {
88
+ 'is_echo' => true,
89
+ 'app_id' => 184_719_329_217_930_001,
90
+ 'mid' => 'mid.1457764197618:41d102a3e1ae206a48',
91
+ 'attachments' => [{
92
+ 'type' => 'audio',
93
+ 'payload' => {
94
+ 'url' => 'https://www.example.com/4.ogg'
95
+ }
96
+ }]
97
+ }
98
+ }
99
+ end
100
+
101
+ let :location_payload do
102
+ {
103
+ 'sender' => {
104
+ 'id' => '6'
105
+ },
106
+ 'recipient' => {
107
+ 'id' => '9'
108
+ },
109
+ 'timestamp' => 145_776_429_762_4,
110
+ 'message' => {
111
+ 'is_echo' => true,
112
+ 'app_id' => 184_719_329_222_930_001,
113
+ 'mid' => 'mid.1457764197618:41d102a3e1ae206a38',
114
+ 'attachments' => [{
115
+ 'type' => 'location',
116
+ 'payload' => {
117
+ 'coordinates' => {
118
+ 'lat' => '39.920_770',
119
+ 'long' => '40.920_770'
120
+ }
121
+ }
122
+ }]
123
+ }
124
+ }
125
+ end
126
+
127
+ subject { Bobot::Event::MessageEcho.new(payload) }
128
+
129
+ describe '.messaging' do
130
+ it 'returns the original payload' do
131
+ expect(subject.messaging).to eq(payload)
132
+ end
133
+ end
134
+
135
+ describe '.id' do
136
+ it 'returns the message echo id' do
137
+ expect(subject.id).to eq(payload['message']['mid'])
138
+ end
139
+ end
140
+
141
+ describe '.sender' do
142
+ it 'returns the sender' do
143
+ expect(subject.sender).to eq(payload['sender'])
144
+ end
145
+ end
146
+
147
+ describe '.recipient' do
148
+ it 'returns the recipient' do
149
+ expect(subject.recipient).to eq(payload['recipient'])
150
+ end
151
+ end
152
+
153
+ describe '.seq' do
154
+ it 'returns the message echo sequence number' do
155
+ expect(subject.seq).to eq(payload['message']['seq'])
156
+ end
157
+ end
158
+
159
+ describe '.sent_at' do
160
+ it 'returns when the message echo was sent' do
161
+ expect(subject.sent_at).to eq(Time.zone.at(payload['timestamp'] / 1000))
162
+ end
163
+ end
164
+
165
+ describe '.text' do
166
+ it 'returns the text of the message echo' do
167
+ expect(subject.text).to eq(payload['message']['text'])
168
+ end
169
+ end
170
+
171
+ describe '.echo?' do
172
+ it 'returns the echo status of the message echo' do
173
+ expect(subject.echo?).to eq(payload['message']['is_echo'])
174
+ end
175
+ end
176
+
177
+ describe '.attachments' do
178
+ it 'returns the message echo attachments' do
179
+ expect(subject.attachments).to eq(payload['message']['attachments'])
180
+ end
181
+ end
182
+
183
+ describe '.image_attachment?' do
184
+ it 'returns whether the attachment is an image' do
185
+ expect(subject.image_attachment?).to be(true)
186
+ end
187
+ end
188
+
189
+ describe '.video_attachment?' do
190
+ subject { Bobot::Event::MessageEcho.new(video_payload) }
191
+
192
+ it 'returns whether the attachment is a video' do
193
+ expect(subject.video_attachment?).to be(true)
194
+ end
195
+ end
196
+
197
+ describe '.location_attachment?' do
198
+ subject { Bobot::Event::MessageEcho.new(location_payload) }
199
+
200
+ it 'returns whether the attachment is a video' do
201
+ expect(subject.location_attachment?).to be(true)
202
+ end
203
+ end
204
+
205
+ describe '.audio_attachment?' do
206
+ subject { Bobot::Event::MessageEcho.new(audio_payload) }
207
+
208
+ it 'returns whether the attachment is an audio' do
209
+ expect(subject.audio_attachment?).to be(true)
210
+ end
211
+ end
212
+
213
+ describe '.file_attachment?' do
214
+ subject { Bobot::Event::MessageEcho.new(file_payload) }
215
+
216
+ it 'returns whether the attachment is a file' do
217
+ expect(subject.file_attachment?).to be(true)
218
+ end
219
+ end
220
+
221
+ describe '.location_coordinates' do
222
+ subject { Bobot::Event::MessageEcho.new(location_payload) }
223
+
224
+ let(:attachments) { location_payload['message']['attachments'] }
225
+
226
+ it 'returns array of lat long coordinates' do
227
+ expect(subject.location_coordinates).to eq(
228
+ [
229
+ attachments.first['payload']['coordinates']['lat'],
230
+ attachments.first['payload']['coordinates']['long']
231
+ ]
232
+ )
233
+ end
234
+ end
235
+
236
+ describe '.attachment_type' do
237
+ it 'returns the type of the attachment' do
238
+ expect(subject.attachment_type).to eq(
239
+ payload['message']['attachments'].first['type']
240
+ )
241
+ end
242
+ end
243
+
244
+ describe '.attachment_url' do
245
+ it 'returns the url of the attachment' do
246
+ expect(subject.attachment_url).to eq(
247
+ payload['message']['attachments'].first['payload']['url']
248
+ )
249
+ end
250
+ end
251
+ describe '.app_id' do
252
+ it 'returns the app_id from which the message echo was sent' do
253
+ expect(subject.app_id).to eq(payload['message']['app_id'])
254
+ end
255
+ end
256
+
257
+ describe '.quick_reply' do
258
+ context 'when a quick reply was used' do
259
+ it 'returns the payload of the quick reply' do
260
+ expect(subject.quick_reply).to eq(
261
+ payload['message']['quick_reply']['payload']
262
+ )
263
+ end
264
+ end
265
+
266
+ context 'when a quick reply was not used' do
267
+ before do
268
+ payload['message'].delete('quick_reply')
269
+ end
270
+
271
+ it 'returns nil' do
272
+ expect(subject.quick_reply).to eq(nil)
273
+ end
274
+ end
275
+ end
276
+ end