warb 0.1.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/CHANGELOG.md +25 -0
- data/README.md +135 -0
- data/Rakefile +12 -0
- data/docs/README.md +16 -0
- data/docs/components/README.md +24 -0
- data/docs/components/address.md +68 -0
- data/docs/components/button.md +61 -0
- data/docs/components/copy_code_button.md +57 -0
- data/docs/components/cta_action.md +13 -0
- data/docs/components/email.md +40 -0
- data/docs/components/list_action.md +29 -0
- data/docs/components/name.md +49 -0
- data/docs/components/org.md +42 -0
- data/docs/components/phone.md +57 -0
- data/docs/components/reply_button_action.md +32 -0
- data/docs/components/row.md +13 -0
- data/docs/components/section.md +30 -0
- data/docs/components/url.md +40 -0
- data/docs/components/url_button.md +57 -0
- data/docs/images/contact-with-wa_id.png +0 -0
- data/docs/images/contact-without-wa_id.png +0 -0
- data/docs/messages/README.md +80 -0
- data/docs/messages/audio.md +119 -0
- data/docs/messages/contact.md +134 -0
- data/docs/messages/document.md +122 -0
- data/docs/messages/flow.md +12 -0
- data/docs/messages/image.md +116 -0
- data/docs/messages/indicator.md +39 -0
- data/docs/messages/interactive_call_to_action_url.md +96 -0
- data/docs/messages/interactive_list.md +159 -0
- data/docs/messages/interactive_reply_button.md +67 -0
- data/docs/messages/location.md +34 -0
- data/docs/messages/location_request.md +21 -0
- data/docs/messages/reaction.md +23 -0
- data/docs/messages/sticker.md +116 -0
- data/docs/messages/template.md +327 -0
- data/docs/messages/text.md +47 -0
- data/docs/messages/video.md +116 -0
- data/docs/resources/currency.md +22 -0
- data/docs/resources/date_time.md +11 -0
- data/docs/resources/index.md +14 -0
- data/docs/resources/text.md +9 -0
- data/docs/setup.md +46 -0
- data/docs/webhook.md +24 -0
- data/examples/audio.rb +86 -0
- data/examples/document.rb +116 -0
- data/examples/image.rb +97 -0
- data/examples/interactive_call_to_action_url.rb +177 -0
- data/examples/interactive_list.rb +201 -0
- data/examples/interactive_reply_button.rb +174 -0
- data/examples/location.rb +85 -0
- data/examples/location_request.rb +55 -0
- data/examples/message.rb +61 -0
- data/examples/sticker.rb +86 -0
- data/examples/video.rb +96 -0
- data/examples/webhook.rb +144 -0
- data/lib/warb/client.rb +46 -0
- data/lib/warb/components/action.rb +121 -0
- data/lib/warb/components/address.rb +31 -0
- data/lib/warb/components/button.rb +29 -0
- data/lib/warb/components/component.rb +19 -0
- data/lib/warb/components/copy_code_button.rb +30 -0
- data/lib/warb/components/email.rb +21 -0
- data/lib/warb/components/name.rb +29 -0
- data/lib/warb/components/org.rb +23 -0
- data/lib/warb/components/phone.rb +23 -0
- data/lib/warb/components/quick_reply_button.rb +15 -0
- data/lib/warb/components/url.rb +21 -0
- data/lib/warb/components/url_button.rb +30 -0
- data/lib/warb/components/voice_call_button.rb +15 -0
- data/lib/warb/configuration.rb +13 -0
- data/lib/warb/connection.rb +47 -0
- data/lib/warb/dispatcher.rb +16 -0
- data/lib/warb/dispatcher_concern.rb +73 -0
- data/lib/warb/indicator_dispatcher.rb +31 -0
- data/lib/warb/language.rb +8 -0
- data/lib/warb/media_dispatcher.rb +46 -0
- data/lib/warb/resources/audio.rb +19 -0
- data/lib/warb/resources/contact.rb +89 -0
- data/lib/warb/resources/currency.rb +45 -0
- data/lib/warb/resources/date_time.rb +34 -0
- data/lib/warb/resources/document.rb +32 -0
- data/lib/warb/resources/flow.rb +34 -0
- data/lib/warb/resources/image.rb +31 -0
- data/lib/warb/resources/interactive_call_to_action_url.rb +48 -0
- data/lib/warb/resources/interactive_list.rb +36 -0
- data/lib/warb/resources/interactive_reply_button.rb +48 -0
- data/lib/warb/resources/location.rb +31 -0
- data/lib/warb/resources/location_request.rb +24 -0
- data/lib/warb/resources/reaction.rb +19 -0
- data/lib/warb/resources/resource.rb +59 -0
- data/lib/warb/resources/sticker.rb +19 -0
- data/lib/warb/resources/template.rb +166 -0
- data/lib/warb/resources/text.rb +47 -0
- data/lib/warb/resources/video.rb +31 -0
- data/lib/warb/template_dispatcher.rb +10 -0
- data/lib/warb/utils.rb +5 -0
- data/lib/warb/version.rb +5 -0
- data/lib/warb.rb +69 -0
- data/sig/warb.rbs +4 -0
- metadata +172 -0
data/examples/webhook.rb
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
require "sinatra/base"
|
|
2
|
+
require "faraday"
|
|
3
|
+
|
|
4
|
+
class Webhook < Sinatra::Base
|
|
5
|
+
configure do
|
|
6
|
+
set :bind, "0.0.0.0"
|
|
7
|
+
set :port, 3000
|
|
8
|
+
set :host_authorization, { permitted_hosts: [] }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
post "/webhook" do
|
|
12
|
+
request_body = JSON.parse(request.body.read)
|
|
13
|
+
|
|
14
|
+
puts "\n🪝 Incoming webhook message: #{request_body}"
|
|
15
|
+
|
|
16
|
+
message = request_body.dig("entry", 0, "changes", 0, "value", "messages", 0)
|
|
17
|
+
|
|
18
|
+
if message && message["type"] == "text"
|
|
19
|
+
message_id = message["id"]
|
|
20
|
+
|
|
21
|
+
Warb.indicator.mark_as_read(message_id)
|
|
22
|
+
|
|
23
|
+
Warb.message.dispatch(message["from"], reply_to: message_id, message: "Echo #{message["text"]["body"]}")
|
|
24
|
+
|
|
25
|
+
reaction = {
|
|
26
|
+
message_id:,
|
|
27
|
+
emoji: "✅"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Warb.reaction.dispatch(message["from"], **reaction)
|
|
31
|
+
elsif message && message["type"] == "location"
|
|
32
|
+
message_id = message["id"]
|
|
33
|
+
|
|
34
|
+
Warb.indicator.mark_as_read(message_id)
|
|
35
|
+
|
|
36
|
+
# indicate the response is being processed
|
|
37
|
+
Warb.indicator.send_typing_indicator(message_id)
|
|
38
|
+
|
|
39
|
+
# wait a little before send the actual response, so the user can see the typing indicator
|
|
40
|
+
sleep 2
|
|
41
|
+
|
|
42
|
+
location = {
|
|
43
|
+
latitude: message["location"]["latitude"],
|
|
44
|
+
longitude: message["location"]["longitude"],
|
|
45
|
+
name: message["location"]["name"],
|
|
46
|
+
address: message["location"]["address"]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Warb.location.dispatch(message["from"], reply_to: message_id, **location)
|
|
50
|
+
elsif message && message["type"] == "image"
|
|
51
|
+
message_id = message["id"]
|
|
52
|
+
|
|
53
|
+
Warb.indicator.mark_as_read(message_id)
|
|
54
|
+
|
|
55
|
+
# for images, documents, videos, audios and stickers, you may need to keep the respective field id
|
|
56
|
+
# the respective ids are:
|
|
57
|
+
# message["image"]["id"]
|
|
58
|
+
# message["sticker"]["id"]
|
|
59
|
+
# message["audio"]["id"]
|
|
60
|
+
# message["document"]["id"]
|
|
61
|
+
# message["video"]["id"]
|
|
62
|
+
#
|
|
63
|
+
# and only one of them is presented within the webhook response data
|
|
64
|
+
#
|
|
65
|
+
# with the media id in hands, you can re-send it and/or download it
|
|
66
|
+
#
|
|
67
|
+
# below, we resend the received image, using its id.
|
|
68
|
+
|
|
69
|
+
image = {
|
|
70
|
+
media_id: message["image"]["id"],
|
|
71
|
+
link: message["image"]["link"],
|
|
72
|
+
caption: message["image"]["caption"]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
Warb.image.dispatch(message["from"], reply_to: message_id, **image)
|
|
76
|
+
|
|
77
|
+
# and here, we download the received image
|
|
78
|
+
Warb.image.download(media_id: image[:media_id], file_path: "#{Time.now}.jpg")
|
|
79
|
+
elsif message && message["type"] == "document"
|
|
80
|
+
message_id = message["id"]
|
|
81
|
+
|
|
82
|
+
Warb.indicator.mark_as_read(message_id)
|
|
83
|
+
|
|
84
|
+
document = {
|
|
85
|
+
id: message["document"]["id"],
|
|
86
|
+
link: message["document"]["link"],
|
|
87
|
+
caption: message["document"]["caption"],
|
|
88
|
+
filename: message["document"]["filename"]
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
Warb.document.dispatch(message["from"], reply_to: message_id, **document)
|
|
92
|
+
elsif message && message["type"] == "sticker"
|
|
93
|
+
message_id = message["id"]
|
|
94
|
+
|
|
95
|
+
Warb.indicator.mark_as_read(message_id)
|
|
96
|
+
|
|
97
|
+
sticker = {
|
|
98
|
+
media_id: message["sticker"]["id"],
|
|
99
|
+
link: message["sticker"]["link"]
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
Warb.sticker.dispatch(message["from"], reply_to: message_id, **sticker)
|
|
103
|
+
# you could keep adding verifications for different types of messages...
|
|
104
|
+
# elsif message && message["type"] == "image"
|
|
105
|
+
# elsif message && message["type"] == "video"
|
|
106
|
+
# elsif message && message["type"] == "contacts ?"
|
|
107
|
+
# elsif message && message["type"] == "button"
|
|
108
|
+
# elsif message && message["type"] == "interactive"
|
|
109
|
+
# elsif message && message["type"] == "unknown"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
status 200
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# this is the endpoint which gets called to verify the server within the Meta's API
|
|
116
|
+
# you can do whatever you want here to verify your server
|
|
117
|
+
# returning the challenge value which was received as query param is enough
|
|
118
|
+
get "/webhook" do
|
|
119
|
+
mode = params["hub.mode"]
|
|
120
|
+
token = params["hub.verify_token"]
|
|
121
|
+
challenge = params["hub.challenge"]
|
|
122
|
+
|
|
123
|
+
if mode == "subscribe" && token == Warb.configuration.webhook_verify_token
|
|
124
|
+
status 200
|
|
125
|
+
body challenge
|
|
126
|
+
|
|
127
|
+
puts "\n✨ Webhook verified successfully!"
|
|
128
|
+
else
|
|
129
|
+
status 403
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
run! if app_file == $PROGRAM_NAME
|
|
134
|
+
|
|
135
|
+
private
|
|
136
|
+
|
|
137
|
+
def conn
|
|
138
|
+
@conn ||= Faraday.new("https://graph.facebook.com/v22.0") do |conn|
|
|
139
|
+
conn.headers["Authorization"] = "Bearer #{Warb.configuration.access_token}" if Warb.configuration.access_token
|
|
140
|
+
conn.request(:json)
|
|
141
|
+
conn.response(:json)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
data/lib/warb/client.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "connection"
|
|
4
|
+
module Warb
|
|
5
|
+
class Client
|
|
6
|
+
include DispatcherConcern
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
attr_reader :access_token, :sender_id, :business_id, :adapter, :logger
|
|
10
|
+
|
|
11
|
+
def_delegators :@configuration, :access_token, :sender_id, :business_id, :adapter, :logger
|
|
12
|
+
|
|
13
|
+
def initialize(configuration = nil, access_token: nil, sender_id: nil, business_id: nil,
|
|
14
|
+
adapter: nil, logger: nil)
|
|
15
|
+
@configuration = (configuration || Warb.configuration).dup
|
|
16
|
+
|
|
17
|
+
@configuration.access_token = access_token || @configuration.access_token
|
|
18
|
+
@configuration.sender_id = sender_id || @configuration.sender_id
|
|
19
|
+
@configuration.business_id = business_id || @configuration.business_id
|
|
20
|
+
@configuration.adapter = adapter || @configuration.adapter
|
|
21
|
+
@configuration.logger = logger || @configuration.logger
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def get(endpoint, data = {}, **args)
|
|
25
|
+
conn.send_request(http_method: "get", endpoint: endpoint, data: data, **args)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def post(endpoint, data = {}, **args)
|
|
29
|
+
conn.send_request(http_method: "post", endpoint: endpoint, data: data, **args)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def put(endpoint, data = {}, **args)
|
|
33
|
+
conn.send_request(http_method: "put", endpoint: endpoint, data: data, **args)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def delete(endpoint, data = {}, **args)
|
|
37
|
+
conn.send_request(http_method: "delete", endpoint: endpoint, data: data, **args)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def conn
|
|
43
|
+
@conn ||= Warb::Connection.new(self)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
module Warb
|
|
2
|
+
module Components
|
|
3
|
+
class Row
|
|
4
|
+
attr_accessor :title, :description
|
|
5
|
+
|
|
6
|
+
def initialize(title: nil, description: nil)
|
|
7
|
+
@title = title
|
|
8
|
+
@description = description
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_h
|
|
12
|
+
{
|
|
13
|
+
title: @title,
|
|
14
|
+
description: @description
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class Section
|
|
20
|
+
attr_accessor :title, :rows
|
|
21
|
+
|
|
22
|
+
def initialize(title: nil, rows: [])
|
|
23
|
+
@title = title
|
|
24
|
+
@rows = rows
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def add_row(**args, &block)
|
|
28
|
+
row = Row.new(**args)
|
|
29
|
+
|
|
30
|
+
@rows << row
|
|
31
|
+
|
|
32
|
+
block_given? ? row.tap(&block) : row
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_h
|
|
36
|
+
{
|
|
37
|
+
title: @title,
|
|
38
|
+
rows: @rows.map.with_index do |row, index|
|
|
39
|
+
row_title = row.title.slice(0, 10)
|
|
40
|
+
title = row_title.normalize.gsub(/\s/, "").downcase
|
|
41
|
+
id = "#{title}_#{index}"
|
|
42
|
+
|
|
43
|
+
row.to_h.merge(id: id)
|
|
44
|
+
end
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class ListAction
|
|
50
|
+
attr_accessor :button_text, :sections
|
|
51
|
+
|
|
52
|
+
def initialize(button_text: nil, sections: [])
|
|
53
|
+
@button_text = button_text
|
|
54
|
+
@sections = sections
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def add_section(**args, &block)
|
|
58
|
+
section = Section.new(**args)
|
|
59
|
+
|
|
60
|
+
@sections << section
|
|
61
|
+
|
|
62
|
+
block_given? ? section.tap(&block) : section
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def to_h
|
|
66
|
+
{
|
|
67
|
+
button: @button_text,
|
|
68
|
+
sections: @sections.map(&:to_h)
|
|
69
|
+
}
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class ReplyButtonAction
|
|
74
|
+
attr_accessor :buttons_texts
|
|
75
|
+
|
|
76
|
+
def initialize(buttons_texts: [])
|
|
77
|
+
@buttons_texts = buttons_texts
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def to_h
|
|
81
|
+
{
|
|
82
|
+
buttons: @buttons_texts.map.with_index do |button_text, index|
|
|
83
|
+
text = button_text.normalize.gsub(/\s/, "").downcase
|
|
84
|
+
id = "#{text}_#{index}"
|
|
85
|
+
|
|
86
|
+
{
|
|
87
|
+
type: "reply",
|
|
88
|
+
reply: {
|
|
89
|
+
id: id,
|
|
90
|
+
title: button_text
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def add_button_text(button_text)
|
|
98
|
+
@buttons_texts << button_text
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class CTAAction
|
|
103
|
+
attr_accessor :button_text, :url
|
|
104
|
+
|
|
105
|
+
def initialize(button_text: nil, url: nil)
|
|
106
|
+
@button_text = button_text
|
|
107
|
+
@url = url
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def to_h
|
|
111
|
+
{
|
|
112
|
+
name: "cta_url",
|
|
113
|
+
parameters: {
|
|
114
|
+
display_text: @button_text,
|
|
115
|
+
url: @url
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Warb
|
|
4
|
+
module Components
|
|
5
|
+
class Address
|
|
6
|
+
attr_accessor :street, :city, :state, :zip, :country, :country_code, :type
|
|
7
|
+
|
|
8
|
+
def initialize(**params)
|
|
9
|
+
@street = params[:street]
|
|
10
|
+
@city = params[:city]
|
|
11
|
+
@state = params[:state]
|
|
12
|
+
@zip = params[:zip]
|
|
13
|
+
@country = params[:country]
|
|
14
|
+
@country_code = params[:country_code]
|
|
15
|
+
@type = params[:type]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_h
|
|
19
|
+
{
|
|
20
|
+
street: street,
|
|
21
|
+
city: city,
|
|
22
|
+
state: state,
|
|
23
|
+
zip: zip,
|
|
24
|
+
country: country,
|
|
25
|
+
country_code: country_code,
|
|
26
|
+
type: type
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Warb
|
|
4
|
+
module Components
|
|
5
|
+
class Button < Component
|
|
6
|
+
attr_accessor :index, :sub_type
|
|
7
|
+
|
|
8
|
+
def initialize(**params)
|
|
9
|
+
params[:sub_type] = button_type unless params[:sub_type]
|
|
10
|
+
|
|
11
|
+
super(**params)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_h
|
|
15
|
+
{
|
|
16
|
+
type: "button",
|
|
17
|
+
sub_type: sub_type || @params[:sub_type],
|
|
18
|
+
index: index || @params[:index]
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def button_type
|
|
25
|
+
raise NotImplementedError
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Warb
|
|
4
|
+
module Components
|
|
5
|
+
class Component
|
|
6
|
+
def initialize(**params)
|
|
7
|
+
@params = params
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_h
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
attr_reader :params
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Warb
|
|
4
|
+
module Components
|
|
5
|
+
class CopyCodeButton < Button
|
|
6
|
+
BUTTON_TYPE = "copy_code"
|
|
7
|
+
|
|
8
|
+
attr_accessor :coupon_code
|
|
9
|
+
|
|
10
|
+
def to_h
|
|
11
|
+
button_payload = super
|
|
12
|
+
|
|
13
|
+
if coupon_code || @params[:coupon_code]
|
|
14
|
+
button_payload[:parameters] = Array.new(1, {
|
|
15
|
+
type: "coupon_code",
|
|
16
|
+
coupon_code: coupon_code || @params[:coupon_code]
|
|
17
|
+
})
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
button_payload
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def button_type
|
|
26
|
+
BUTTON_TYPE
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Warb
|
|
4
|
+
module Components
|
|
5
|
+
class Email
|
|
6
|
+
attr_accessor :type, :email
|
|
7
|
+
|
|
8
|
+
def initialize(**params)
|
|
9
|
+
@type = params[:type]
|
|
10
|
+
@email = params[:email]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_h
|
|
14
|
+
{
|
|
15
|
+
type: type,
|
|
16
|
+
email: email
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Warb
|
|
4
|
+
module Components
|
|
5
|
+
class Name
|
|
6
|
+
attr_accessor :formatted_name, :first_name, :last_name, :middle_name, :suffix, :prefix
|
|
7
|
+
|
|
8
|
+
def initialize(**params)
|
|
9
|
+
@formatted_name = params[:formatted_name]
|
|
10
|
+
@first_name = params[:first_name]
|
|
11
|
+
@last_name = params[:last_name]
|
|
12
|
+
@middle_name = params[:middle_name]
|
|
13
|
+
@suffix = params[:suffix]
|
|
14
|
+
@prefix = params[:prefix]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_h
|
|
18
|
+
{
|
|
19
|
+
formatted_name: formatted_name,
|
|
20
|
+
first_name: first_name,
|
|
21
|
+
last_name: last_name,
|
|
22
|
+
middle_name: middle_name,
|
|
23
|
+
suffix: suffix,
|
|
24
|
+
prefix: prefix
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Warb
|
|
4
|
+
module Components
|
|
5
|
+
class Org
|
|
6
|
+
attr_accessor :company, :department, :title
|
|
7
|
+
|
|
8
|
+
def initialize(**params)
|
|
9
|
+
@company = params[:company]
|
|
10
|
+
@department = params[:department]
|
|
11
|
+
@title = params[:title]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_h
|
|
15
|
+
{
|
|
16
|
+
company: company,
|
|
17
|
+
department: department,
|
|
18
|
+
title: title
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Warb
|
|
4
|
+
module Components
|
|
5
|
+
class Phone
|
|
6
|
+
attr_accessor :phone, :type, :wa_id
|
|
7
|
+
|
|
8
|
+
def initialize(**params)
|
|
9
|
+
@phone = params[:phone]
|
|
10
|
+
@type = params[:type]
|
|
11
|
+
@wa_id = params[:wa_id]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_h
|
|
15
|
+
{
|
|
16
|
+
phone: phone,
|
|
17
|
+
type: type,
|
|
18
|
+
wa_id: wa_id
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Warb
|
|
4
|
+
module Components
|
|
5
|
+
class URL
|
|
6
|
+
attr_accessor :url, :type
|
|
7
|
+
|
|
8
|
+
def initialize(**params)
|
|
9
|
+
@type = params[:type]
|
|
10
|
+
@url = params[:url]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_h
|
|
14
|
+
{
|
|
15
|
+
type: type,
|
|
16
|
+
url: url
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Warb
|
|
4
|
+
module Components
|
|
5
|
+
class UrlButton < Button
|
|
6
|
+
BUTTON_TYPE = "url"
|
|
7
|
+
|
|
8
|
+
attr_accessor :text
|
|
9
|
+
|
|
10
|
+
def to_h
|
|
11
|
+
button_payload = super
|
|
12
|
+
|
|
13
|
+
if text || @params[:text]
|
|
14
|
+
button_payload[:parameters] = Array.new(1, {
|
|
15
|
+
type: "text",
|
|
16
|
+
text: text || @params[:text]
|
|
17
|
+
})
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
button_payload
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def button_type
|
|
26
|
+
BUTTON_TYPE
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Warb
|
|
2
|
+
class Configuration
|
|
3
|
+
attr_accessor :access_token, :sender_id, :business_id, :adapter, :logger
|
|
4
|
+
|
|
5
|
+
def initialize(access_token: nil, sender_id: nil, business_id: nil, adapter: nil, logger: nil)
|
|
6
|
+
@access_token = access_token
|
|
7
|
+
@sender_id = sender_id
|
|
8
|
+
@business_id = business_id
|
|
9
|
+
@adapter = adapter || Faraday.default_adapter
|
|
10
|
+
@logger = logger || Logger.new($stdout)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Warb
|
|
4
|
+
class Connection
|
|
5
|
+
attr_reader :client
|
|
6
|
+
|
|
7
|
+
def initialize(client)
|
|
8
|
+
@client = client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def send_request(http_method:, endpoint:, url: nil, data: {}, headers: {}, multipart: false,
|
|
12
|
+
endpoint_prefix: :sender_id)
|
|
13
|
+
conn = set_connection(url:, multipart:)
|
|
14
|
+
conn.send(http_method, handle_endpoint(endpoint:, endpoint_prefix:), data, headers)
|
|
15
|
+
rescue StandardError => e
|
|
16
|
+
@client.logger.error e.inspect
|
|
17
|
+
e.response
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def set_connection(url:, multipart:)
|
|
23
|
+
url ||= "https://graph.facebook.com/v22.0"
|
|
24
|
+
|
|
25
|
+
Faraday.new(url) do |conn|
|
|
26
|
+
conn.request(:multipart) if multipart
|
|
27
|
+
conn.request(:url_encoded) if multipart
|
|
28
|
+
conn.request(:json)
|
|
29
|
+
conn.response(:json)
|
|
30
|
+
conn.headers["Authorization"] = "Bearer #{@client.access_token}" unless @client.access_token.nil?
|
|
31
|
+
conn.adapter(@client.adapter)
|
|
32
|
+
conn.response :raise_error
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def handle_endpoint(endpoint:, endpoint_prefix:)
|
|
37
|
+
case endpoint_prefix
|
|
38
|
+
when :sender_id
|
|
39
|
+
"#{@client.sender_id}/#{endpoint}"
|
|
40
|
+
when :business_id
|
|
41
|
+
"#{@client.business_id}/#{endpoint}"
|
|
42
|
+
else
|
|
43
|
+
endpoint
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Warb
|
|
2
|
+
class Dispatcher
|
|
3
|
+
def initialize(klass, client)
|
|
4
|
+
@klass = klass
|
|
5
|
+
@client = client
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def dispatch(recipient_number, reply_to: nil, **args, &block)
|
|
9
|
+
resource = block_given? ? @klass.new(**args).tap(&block) : @klass.new(**args)
|
|
10
|
+
|
|
11
|
+
data = resource.call(recipient_number, reply_to:)
|
|
12
|
+
|
|
13
|
+
@client.post("messages", data)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|