bobot 1.0.52
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +66 -0
- data/Rakefile +19 -0
- data/app/controllers/bobot/application_controller.rb +5 -0
- data/app/controllers/bobot/webhook_controller.rb +76 -0
- data/app/jobs/bobot/application_job.rb +4 -0
- data/app/jobs/bobot/commander_job.rb +9 -0
- data/app/jobs/bobot/deliver_job.rb +16 -0
- data/app/mailers/bobot/application_mailer.rb +6 -0
- data/app/models/bobot/application_record.rb +5 -0
- data/config/locales/bobot.en.yml +28 -0
- data/config/routes.rb +6 -0
- data/lib/bobot.rb +18 -0
- data/lib/bobot/buttons.rb +168 -0
- data/lib/bobot/commander.rb +68 -0
- data/lib/bobot/configuration.rb +206 -0
- data/lib/bobot/engine.rb +33 -0
- data/lib/bobot/error_parser.rb +102 -0
- data/lib/bobot/event.rb +40 -0
- data/lib/bobot/events/account_linking.rb +15 -0
- data/lib/bobot/events/common.rb +170 -0
- data/lib/bobot/events/delivery.rb +20 -0
- data/lib/bobot/events/message.rb +72 -0
- data/lib/bobot/events/message_echo.rb +8 -0
- data/lib/bobot/events/optin.rb +11 -0
- data/lib/bobot/events/postback.rb +20 -0
- data/lib/bobot/events/read.rb +15 -0
- data/lib/bobot/events/referral.rb +33 -0
- data/lib/bobot/exceptions.rb +73 -0
- data/lib/bobot/graph_facebook.rb +90 -0
- data/lib/bobot/profile.rb +23 -0
- data/lib/bobot/subscription.rb +19 -0
- data/lib/bobot/user.rb +13 -0
- data/lib/bobot/version.rb +14 -0
- data/lib/generators/bobot/install_generator.rb +28 -0
- data/lib/generators/bobot/templates/app/bobot/message.rb +3 -0
- data/lib/generators/bobot/templates/app/bobot/postback.rb +22 -0
- data/lib/generators/bobot/templates/app/bobot/workflow.rb +17 -0
- data/lib/generators/bobot/templates/config/bobot.yml +39 -0
- data/lib/generators/bobot/templates/config/initializers/bobot.rb +30 -0
- data/lib/generators/bobot/templates/config/locales/bobot.en.yml +30 -0
- data/lib/generators/bobot/templates/config/locales/bobot.fr.yml +29 -0
- data/lib/generators/bobot/uninstall_generator.rb +24 -0
- data/lib/generators/bobot/utils.rb +30 -0
- data/lib/tasks/bobot_tasks.rake +11 -0
- data/spec/bobot/bobot_spec.rb +24 -0
- data/spec/bobot/event/account_linking_spec.rb +59 -0
- data/spec/bobot/event/common_spec.rb +259 -0
- data/spec/bobot/event/delivery_spec.rb +62 -0
- data/spec/bobot/event/message_echo_spec.rb +276 -0
- data/spec/bobot/event/message_spec.rb +276 -0
- data/spec/bobot/event/optin_spec.rb +50 -0
- data/spec/bobot/event/postback_spec.rb +94 -0
- data/spec/bobot/event/read_spec.rb +51 -0
- data/spec/bobot/event/referral_spec.rb +66 -0
- data/spec/bobot/event_spec.rb +167 -0
- data/spec/bobot/install_generator_spec.rb +43 -0
- data/spec/bobot/profile_spec.rb +170 -0
- data/spec/bobot/subscription_spec.rb +139 -0
- data/spec/bobot/user_spec.rb +91 -0
- data/spec/controllers/bobot/application_controller_spec.rb +4 -0
- data/spec/controllers/bobot/webhook_controller_spec.rb +5 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +3 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/bobot/workflow.rb +17 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/jobs/application_job.rb +2 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +35 -0
- data/spec/dummy/bin/update +29 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/config/application.rb +30 -0
- data/spec/dummy/config/bobot.yml +27 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +19 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +42 -0
- data/spec/dummy/config/environments/production.rb +78 -0
- data/spec/dummy/config/environments/test.rb +38 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/bobot.rb +30 -0
- data/spec/dummy/config/initializers/cors.rb +16 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/bobot.en.yml +28 -0
- data/spec/dummy/config/locales/bobot.fr.yml +27 -0
- data/spec/dummy/config/locales/en.yml +33 -0
- data/spec/dummy/config/puma.rb +56 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/secrets.yml +32 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/db/schema.rb +15 -0
- data/spec/examples.txt +111 -0
- data/spec/helpers/graph_api_helpers.rb +6 -0
- data/spec/jobs/bobot/commander_job_spec.rb +31 -0
- data/spec/lint/rubocop_spec.rb +8 -0
- data/spec/rails_helper.rb +67 -0
- data/spec/spec_helper.rb +105 -0
- data/spec/travis/database.travis.mysql.yml +19 -0
- metadata +251 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Bobot
|
|
2
|
+
module Commander
|
|
3
|
+
class Error < Bobot::FacebookError; end
|
|
4
|
+
|
|
5
|
+
EVENTS = %i[
|
|
6
|
+
message
|
|
7
|
+
delivery
|
|
8
|
+
postback
|
|
9
|
+
optin
|
|
10
|
+
read
|
|
11
|
+
account_linking
|
|
12
|
+
referral
|
|
13
|
+
message_echo
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
include Bobot::GraphFacebook
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def deliver(body:, query:)
|
|
20
|
+
graph_post '/me/messages', body: body, query: {
|
|
21
|
+
access_token: query.fetch(:access_token),
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def on(event, &block)
|
|
26
|
+
unless EVENTS.include? event
|
|
27
|
+
raise Error.new("#{event} is not a valid event; available events are #{EVENTS.join(',')}")
|
|
28
|
+
end
|
|
29
|
+
hooks[event] = block
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def receive(payload)
|
|
33
|
+
event = Bobot::Event.parse(payload)
|
|
34
|
+
hooks.fetch(Bobot::Event::EVENTS.invert[event.class].to_sym)
|
|
35
|
+
puts "[ActiveJob] << Bobot::HookJob with event #{event.class}" if Bobot.debug_log
|
|
36
|
+
#event.mark_as_seen
|
|
37
|
+
job = Bobot::CommanderJob
|
|
38
|
+
if Bobot.async
|
|
39
|
+
job.perform_later(payload: payload)
|
|
40
|
+
else
|
|
41
|
+
job.perform_now(payload: payload)
|
|
42
|
+
end
|
|
43
|
+
rescue KeyError
|
|
44
|
+
$stderr.puts "Ignoring #{event.class} (no hook registered)"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def trigger(payload)
|
|
48
|
+
event = Bobot::Event.parse(payload)
|
|
49
|
+
hook = hooks.fetch(Bobot::Event::EVENTS.invert[event.class].to_sym)
|
|
50
|
+
puts "[ActiveJob] >> Bobot::HookJob related to event #{name.class}" if Bobot.debug_log
|
|
51
|
+
#event.show_typing(state: true)
|
|
52
|
+
hook.call(event)
|
|
53
|
+
#event.show_typing(state: false)
|
|
54
|
+
[event, event.payloads_sent[1..-2]]
|
|
55
|
+
rescue KeyError
|
|
56
|
+
$stderr.puts "Ignoring #{event.class} (no hook registered)"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def hooks
|
|
60
|
+
@hooks ||= {}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def unhook
|
|
64
|
+
@hooks = {}
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
module Bobot
|
|
2
|
+
# Defines constants and methods related to configuration
|
|
3
|
+
module Configuration
|
|
4
|
+
# An array of valid keys in the options hash when configuring
|
|
5
|
+
VALID_CONFIGURATION_KEYS = %i[
|
|
6
|
+
page_id
|
|
7
|
+
app_id
|
|
8
|
+
app_secret
|
|
9
|
+
page_access_token
|
|
10
|
+
verify_token
|
|
11
|
+
domains
|
|
12
|
+
debug_log
|
|
13
|
+
async
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
# By default, don't set a facebook page id
|
|
17
|
+
DEFAULT_PAGE_ID = nil
|
|
18
|
+
|
|
19
|
+
# By default, don't set a facebook developper app id
|
|
20
|
+
DEFAULT_APP_ID = nil
|
|
21
|
+
|
|
22
|
+
# By default, don't set a facebook developper app secret
|
|
23
|
+
DEFAULT_APP_SECRET = nil
|
|
24
|
+
|
|
25
|
+
# By default, don't set a facebook developper page access token
|
|
26
|
+
DEFAULT_PAGE_ACCESS_TOKEN = nil
|
|
27
|
+
|
|
28
|
+
# By default, don't set a facebook webhook_verify_token
|
|
29
|
+
DEFAULT_VERIFY_TOKEN = nil
|
|
30
|
+
|
|
31
|
+
# By default, don't set a facebook whitelisting domains
|
|
32
|
+
DEFAULT_DOMAINS = nil
|
|
33
|
+
|
|
34
|
+
# By default, debug log is to false
|
|
35
|
+
DEFAULT_DEBUG_LOG = false
|
|
36
|
+
|
|
37
|
+
# By default, async is to false
|
|
38
|
+
DEFAULT_ASYNC = false
|
|
39
|
+
|
|
40
|
+
# @private
|
|
41
|
+
attr_accessor(*VALID_CONFIGURATION_KEYS)
|
|
42
|
+
|
|
43
|
+
# Our host application root path
|
|
44
|
+
# We set this when the engine is initialized
|
|
45
|
+
mattr_accessor :app_root
|
|
46
|
+
|
|
47
|
+
# When this module is extended, set all configuration options to their default values
|
|
48
|
+
def self.extended(base)
|
|
49
|
+
base.reset!
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Convenience method to allow configuration options to be set in a block
|
|
53
|
+
def configure
|
|
54
|
+
yield self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Custom self assignments
|
|
58
|
+
def domains=(rhs)
|
|
59
|
+
return unless rhs.present?
|
|
60
|
+
if rhs.respond_to?(:to_str)
|
|
61
|
+
@domains = rhs.split(",").map(&:strip)
|
|
62
|
+
elsif rhs.is_a?(Array)
|
|
63
|
+
@domains = rhs
|
|
64
|
+
else
|
|
65
|
+
raise Bobot::InvalidParameter.new(:domains, "should be a string or an array")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Create a hash of options and their values
|
|
70
|
+
def configurations
|
|
71
|
+
VALID_CONFIGURATION_KEYS.inject({}) do |option, key|
|
|
72
|
+
option.merge!(key => send(key))
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Reset all configuration options to defaults
|
|
77
|
+
def reset!
|
|
78
|
+
self.page_id = DEFAULT_PAGE_ID
|
|
79
|
+
self.app_id = DEFAULT_APP_ID
|
|
80
|
+
self.app_secret = DEFAULT_APP_SECRET
|
|
81
|
+
self.page_access_token = DEFAULT_PAGE_ACCESS_TOKEN
|
|
82
|
+
self.verify_token = DEFAULT_VERIFY_TOKEN
|
|
83
|
+
self.domains = DEFAULT_DOMAINS
|
|
84
|
+
self.debug_log = DEFAULT_DEBUG_LOG
|
|
85
|
+
self.async = DEFAULT_ASYNC
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def update_facebook_setup!
|
|
89
|
+
subscribe_to_facebook_page!
|
|
90
|
+
set_greeting_text!
|
|
91
|
+
set_whitelist_domains!
|
|
92
|
+
set_get_started_button!
|
|
93
|
+
set_persistent_menu!
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
## == Subcribe your bot to your page ==
|
|
97
|
+
def subscribe_to_facebook_page!
|
|
98
|
+
raise Bobot::InvalidParameter.new(:page_id) unless Bobot.page_id.present?
|
|
99
|
+
raise Bobot::InvalidParameter.new(:access_token) unless Bobot.page_access_token.present?
|
|
100
|
+
Bobot::Subscription.set(
|
|
101
|
+
query: {
|
|
102
|
+
page_id: Bobot.page_id,
|
|
103
|
+
access_token: Bobot.page_access_token,
|
|
104
|
+
},
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
## == Unsubcribe your bot from your page ==
|
|
109
|
+
def unsubscribe_to_facebook_page!
|
|
110
|
+
raise Bobot::InvalidParameter.new(:page_id) unless Bobot.page_id.present?
|
|
111
|
+
raise Bobot::InvalidParameter.new(:access_token) unless Bobot.page_access_token.present?
|
|
112
|
+
Bobot::Subscription.unset(
|
|
113
|
+
query: {
|
|
114
|
+
page_id: Bobot.page_id,
|
|
115
|
+
access_token: Bobot.page_access_token,
|
|
116
|
+
},
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
## == Set bot description (only displayed on first time). ==
|
|
121
|
+
def set_greeting_text!
|
|
122
|
+
raise Bobot::InvalidParameter.new(:access_token) unless Bobot.page_access_token.present?
|
|
123
|
+
greeting_texts = []
|
|
124
|
+
# Default text
|
|
125
|
+
greeting_text = I18n.t('bobot.config.greeting_text', locale: I18n.default_locale, default: nil)
|
|
126
|
+
if greeting_text.present?
|
|
127
|
+
greeting_texts << {
|
|
128
|
+
locale: 'default',
|
|
129
|
+
text: greeting_text,
|
|
130
|
+
}
|
|
131
|
+
end
|
|
132
|
+
# Each languages
|
|
133
|
+
I18n.available_locales.each do |locale|
|
|
134
|
+
greeting_text = I18n.t('bobot.config.greeting_text', locale: locale, default: nil)
|
|
135
|
+
next unless greeting_text.present?
|
|
136
|
+
facebook_locales = I18n.t('bobot.config.facebook_locales', locale: locale, default: nil)
|
|
137
|
+
facebook_locales.to_a.each do |locale_long|
|
|
138
|
+
greeting_texts << { locale: locale_long, text: greeting_text }
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
raise Bobot::InvalidParameter.new(:greeting_texts) unless greeting_texts.present?
|
|
142
|
+
Bobot::Profile.set(
|
|
143
|
+
body: { greeting: greeting_texts },
|
|
144
|
+
query: { access_token: Bobot.page_access_token },
|
|
145
|
+
)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
## == Set bot whitelist domains (only displayed on first time) ==
|
|
149
|
+
## == Some features like Messenger Extensions and Checkbox Plugin require ==
|
|
150
|
+
## == a page to specify a domain whitelist. ==
|
|
151
|
+
def set_whitelist_domains!
|
|
152
|
+
raise Bobot::InvalidParameter.new(:access_token) unless Bobot.page_access_token.present?
|
|
153
|
+
raise Bobot::InvalidParameter.new(:domains) unless Bobot.domains.present?
|
|
154
|
+
Bobot::Profile.set(
|
|
155
|
+
body: { whitelisted_domains: Bobot.domains },
|
|
156
|
+
query: { access_token: Bobot.page_access_token },
|
|
157
|
+
)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
## == You can define the action to trigger when new humans click on ==
|
|
161
|
+
## == the Get Started button. Before doing it you should check to select the ==
|
|
162
|
+
## == messaging_postbacks field when setting up your webhook. ==
|
|
163
|
+
def set_get_started_button!
|
|
164
|
+
raise Bobot::InvalidParameter.new(:access_token) unless Bobot.page_access_token.present?
|
|
165
|
+
Bobot::Profile.set(
|
|
166
|
+
body: { get_started: { payload: I18n.t('bobot.config.get_started.payload') } },
|
|
167
|
+
query: { access_token: Bobot.page_access_token },
|
|
168
|
+
)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
## == You can show a persistent menu to humans. ==
|
|
172
|
+
## == If you want to have a persistent menu, you have to set get_started ==
|
|
173
|
+
## == button before. ==
|
|
174
|
+
def set_persistent_menu!
|
|
175
|
+
raise Bobot::InvalidParameter.new(:access_token) unless Bobot.page_access_token.present?
|
|
176
|
+
persistent_menus = []
|
|
177
|
+
# Default text
|
|
178
|
+
persistent_menu = I18n.t('bobot.config.persistent_menu', locale: I18n.default_locale, default: nil)
|
|
179
|
+
if persistent_menu.present?
|
|
180
|
+
persistent_menus << {
|
|
181
|
+
locale: 'default',
|
|
182
|
+
composer_input_disabled: persistent_menu[:composer_input_disabled],
|
|
183
|
+
call_to_actions: persistent_menu[:call_to_actions],
|
|
184
|
+
}
|
|
185
|
+
end
|
|
186
|
+
# Each languages
|
|
187
|
+
I18n.available_locales.each do |locale|
|
|
188
|
+
persistent_menu = I18n.t('bobot.config.persistent_menu', locale: locale, default: nil)
|
|
189
|
+
facebook_locales = I18n.t('bobot.config.facebook_locales', locale: locale, default: nil)
|
|
190
|
+
next unless persistent_menu.present?
|
|
191
|
+
facebook_locales.to_a.each do |locale_long|
|
|
192
|
+
persistent_menus << {
|
|
193
|
+
locale: locale_long,
|
|
194
|
+
composer_input_disabled: persistent_menu[:composer_input_disabled],
|
|
195
|
+
call_to_actions: persistent_menu[:call_to_actions],
|
|
196
|
+
}
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
raise Bobot::InvalidParameter.new(:persistent_menus) unless persistent_menus.present?
|
|
200
|
+
Bobot::Profile.set(
|
|
201
|
+
body: { persistent_menu: persistent_menus },
|
|
202
|
+
query: { access_token: Bobot.page_access_token },
|
|
203
|
+
)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
data/lib/bobot/engine.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'rails'
|
|
2
|
+
require 'bobot'
|
|
3
|
+
|
|
4
|
+
module Bobot
|
|
5
|
+
class Engine < ::Rails::Engine
|
|
6
|
+
isolate_namespace Bobot
|
|
7
|
+
config.generators.api_only = true
|
|
8
|
+
|
|
9
|
+
config.action_dispatch.rescue_responses['Bobot::ActionNotAllowed'] = :forbidden
|
|
10
|
+
|
|
11
|
+
initializer 'bobot.load_app_root' do |app|
|
|
12
|
+
Bobot.app_root = app.root
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
initializer 'Bobot setup middlewares' do |app|
|
|
16
|
+
app.config.middleware.use ActionDispatch::Flash
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
config.generators do |g|
|
|
20
|
+
g.test_framework :rspec,
|
|
21
|
+
fixtures: true,
|
|
22
|
+
view_specs: false,
|
|
23
|
+
helper_specs: false,
|
|
24
|
+
routing_specs: false,
|
|
25
|
+
controller_specs: true,
|
|
26
|
+
request_specs: true
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
rake_tasks do
|
|
30
|
+
Dir[File.join(File.dirname(__FILE__), '../tasks/*.rake')].each { |f| load f }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
module Bobot
|
|
2
|
+
# Parses and raises Facebook response errors for the send API.
|
|
3
|
+
class ErrorParser
|
|
4
|
+
INTERNAL_ERROR_CODES = {
|
|
5
|
+
1200 => [],
|
|
6
|
+
}.freeze
|
|
7
|
+
|
|
8
|
+
ACCESS_TOKEN_ERROR_CODES = {
|
|
9
|
+
190 => [],
|
|
10
|
+
}.freeze
|
|
11
|
+
|
|
12
|
+
ACCOUNT_LINKING_ERROR_CODES = {
|
|
13
|
+
10_303 => [],
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
LIMIT_ERROR_CODES = {
|
|
17
|
+
4 => [2_018_022],
|
|
18
|
+
100 => [2_018_109],
|
|
19
|
+
613 => [nil],
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
BAD_PARAMETER_ERROR_CODES = {
|
|
23
|
+
100 => [nil, 2_018_001],
|
|
24
|
+
}.freeze
|
|
25
|
+
|
|
26
|
+
PERMISSION_ERROR_CODES = {
|
|
27
|
+
10 => [2_018_065, 2_018_108],
|
|
28
|
+
200 => [1_545_041, 2_018_028, 2_018_027, 2_018_021],
|
|
29
|
+
230 => [nil],
|
|
30
|
+
}.freeze
|
|
31
|
+
|
|
32
|
+
class << self
|
|
33
|
+
# Raise any errors in the given response.
|
|
34
|
+
#
|
|
35
|
+
# response - A HTTParty::Response object.
|
|
36
|
+
#
|
|
37
|
+
# Returns nil if no errors were found, otherwises raises appropriately
|
|
38
|
+
def raise_errors_from(response)
|
|
39
|
+
return false unless response.key?('error')
|
|
40
|
+
|
|
41
|
+
error = response['error']
|
|
42
|
+
|
|
43
|
+
error_code = error['code']
|
|
44
|
+
error_subcode = error['error_subcode']
|
|
45
|
+
|
|
46
|
+
raise_code_only_error(error_code, error) if error_subcode.nil?
|
|
47
|
+
|
|
48
|
+
raise_code_subcode_error(error_code, error_subcode, error)
|
|
49
|
+
|
|
50
|
+
# Default to unidentified error
|
|
51
|
+
raise FacebookError.new(error)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def raise_code_only_error(error_code, args)
|
|
57
|
+
raise InternalError.new(args) if internal_error?(error_code)
|
|
58
|
+
raise AccessTokenError.new(args) if access_token_error?(error_code)
|
|
59
|
+
raise AccountLinkingError.new(args) if account_linking_error?(error_code)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def raise_code_subcode_error(error_code, error_subcode, args)
|
|
63
|
+
raise LimitError.new(args) if limit_error?(error_code, error_subcode)
|
|
64
|
+
raise BadParameterError.new(args) if bad_parameter_error?(error_code, error_subcode)
|
|
65
|
+
raise PermissionError.new(args) if permission_error?(error_code, error_subcode)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def internal_error?(error_code)
|
|
69
|
+
INTERNAL_ERROR_CODES.keys.include? error_code
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def access_token_error?(error_code)
|
|
73
|
+
ACCESS_TOKEN_ERROR_CODES.keys.include? error_code
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def account_linking_error?(error_code)
|
|
77
|
+
ACCOUNT_LINKING_ERROR_CODES.keys.include? error_code
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def limit_error?(error_code, error_subcode)
|
|
81
|
+
limit_errors = LIMIT_ERROR_CODES[error_code]
|
|
82
|
+
return unless limit_errors
|
|
83
|
+
|
|
84
|
+
limit_errors.include? error_subcode
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def bad_parameter_error?(error_code, error_subcode)
|
|
88
|
+
bad_parameter_errors = BAD_PARAMETER_ERROR_CODES[error_code]
|
|
89
|
+
return unless bad_parameter_errors
|
|
90
|
+
|
|
91
|
+
bad_parameter_errors.include? error_subcode
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def permission_error?(error_code, error_subcode)
|
|
95
|
+
permission_errors = PERMISSION_ERROR_CODES[error_code]
|
|
96
|
+
return unless permission_errors
|
|
97
|
+
|
|
98
|
+
permission_errors.include? error_subcode
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/bobot/event.rb
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'bobot/events/common'
|
|
2
|
+
require 'bobot/events/message'
|
|
3
|
+
require 'bobot/events/message_echo'
|
|
4
|
+
require 'bobot/events/delivery'
|
|
5
|
+
require 'bobot/events/postback'
|
|
6
|
+
require 'bobot/events/optin'
|
|
7
|
+
require 'bobot/events/read'
|
|
8
|
+
require 'bobot/events/account_linking'
|
|
9
|
+
require 'bobot/events/referral'
|
|
10
|
+
|
|
11
|
+
module Bobot
|
|
12
|
+
module Event
|
|
13
|
+
EVENTS = {
|
|
14
|
+
'message' => Message,
|
|
15
|
+
'delivery' => Delivery,
|
|
16
|
+
'postback' => Postback,
|
|
17
|
+
'optin' => Optin,
|
|
18
|
+
'read' => Read,
|
|
19
|
+
'account_linking' => AccountLinking,
|
|
20
|
+
'referral' => Referral,
|
|
21
|
+
'message_echo' => MessageEcho,
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
def self.parse(payload)
|
|
25
|
+
return MessageEcho.new(payload) if payload_is_echo?(payload)
|
|
26
|
+
|
|
27
|
+
EVENTS.each do |event, klass|
|
|
28
|
+
return klass.new(payload) if payload.key?(event)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
raise UnknownPayload.new(payload)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.payload_is_echo?(payload)
|
|
35
|
+
payload.key?('message') && payload['message']['is_echo'] == true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class UnknownPayload < Bobot::Error; end
|
|
39
|
+
end
|
|
40
|
+
end
|