warb 1.0.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 +120 -0
- data/Rakefile +12 -0
- data/docs/README.md +13 -0
- data/docs/components/README.md +21 -0
- data/docs/components/address.md +68 -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/images/contact-with-wa_id.png +0 -0
- data/docs/images/contact-without-wa_id.png +0 -0
- data/docs/messages/README.md +79 -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/text.md +47 -0
- data/docs/messages/video.md +116 -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/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/url.rb +21 -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 +69 -0
- data/lib/warb/indicator_dispatcher.rb +31 -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/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 +21 -0
- data/lib/warb/resources/location_request.rb +24 -0
- data/lib/warb/resources/reaction.rb +19 -0
- data/lib/warb/resources/resource.rb +51 -0
- data/lib/warb/resources/sticker.rb +19 -0
- data/lib/warb/resources/text.rb +29 -0
- data/lib/warb/resources/video.rb +31 -0
- data/lib/warb/utils.rb +5 -0
- data/lib/warb/version.rb +5 -0
- data/lib/warb.rb +58 -0
- data/sig/warb.rbs +4 -0
- metadata +153 -0
data/examples/video.rb
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../lib/warb"
|
|
4
|
+
|
|
5
|
+
# Configure your variables here
|
|
6
|
+
|
|
7
|
+
access_token = ""
|
|
8
|
+
business_id = ""
|
|
9
|
+
sender_id = ""
|
|
10
|
+
recipient_number = ""
|
|
11
|
+
|
|
12
|
+
video_link = ""
|
|
13
|
+
|
|
14
|
+
# We recommend testing one section at a time, as it can be overwhelming to see all the messages at once.
|
|
15
|
+
# So you can comment out the sections you don't want to test.
|
|
16
|
+
|
|
17
|
+
# ############################################## #
|
|
18
|
+
# ============== Using Warb.setup ============== #
|
|
19
|
+
# ############################################## #
|
|
20
|
+
|
|
21
|
+
warb_from_setup = Warb.setup do |config|
|
|
22
|
+
config.access_token = access_token
|
|
23
|
+
config.business_id = business_id
|
|
24
|
+
config.sender_id = sender_id
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# To send video using its ID, you may need to retrieve it first, which can be retrieved this way
|
|
28
|
+
file_path = "" # fill this in with the file path pointing to wherever the video is located
|
|
29
|
+
file_type = "" # fill this in with the mimetype of the video to be uploaded. allowed values: "video/3gpp" or "video/mp4"
|
|
30
|
+
video_id = warb_from_setup.video.upload(file_path: file_path, file_type: file_type)
|
|
31
|
+
# if you already have a video id, you can simply replace the above line with such id
|
|
32
|
+
|
|
33
|
+
warb_from_setup.video.dispatch(recipient_number, media_id: video_id)
|
|
34
|
+
warb_from_setup.video.dispatch(recipient_number, media_id: video_id, caption: "OPTIONAL - Image caption")
|
|
35
|
+
warb_from_setup.video.dispatch(recipient_number, link: video_link)
|
|
36
|
+
warb_from_setup.video.dispatch(recipient_number, link: video_link, caption: "OPTIONAL - Image caption")
|
|
37
|
+
|
|
38
|
+
warb_from_setup.video.dispatch(recipient_number) do |builder|
|
|
39
|
+
builder.media_id = video_id
|
|
40
|
+
builder.caption = "OPTIONAL - Image caption"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
warb_from_setup.video.dispatch(recipient_number) do |builder|
|
|
44
|
+
builder.link = video_link
|
|
45
|
+
builder.caption = "OPTIONAL - Image caption"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# ############################################ #
|
|
49
|
+
# ============== Using Warb.new ============== #
|
|
50
|
+
# ############################################ #
|
|
51
|
+
|
|
52
|
+
warb_from_new = Warb.new(
|
|
53
|
+
access_token: access_token,
|
|
54
|
+
business_id: business_id,
|
|
55
|
+
sender_id: sender_id
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Same as stated above, if you need a video id, you can upload it this way
|
|
59
|
+
file_path = "" # fill this in with the file path pointing to wherever the video is located
|
|
60
|
+
file_type = "" # fill this in with the mimetype of the video to be uploaded. allowed values: "video/3gpp" or "video/mp4"
|
|
61
|
+
video_id = warb_from_setup.video.upload(file_path: file_path, file_type: file_type)
|
|
62
|
+
# if you already have a video id, you can simply replace the above line with such id
|
|
63
|
+
|
|
64
|
+
warb_from_new.video.dispatch(recipient_number, media_id: video_id)
|
|
65
|
+
warb_from_new.video.dispatch(recipient_number, media_id: video_id, caption: "OPTIONAL - Image caption")
|
|
66
|
+
warb_from_new.video.dispatch(recipient_number, link: video_link)
|
|
67
|
+
warb_from_new.video.dispatch(recipient_number, link: video_link, caption: "OPTIONAL - Image caption")
|
|
68
|
+
|
|
69
|
+
warb_from_new.video.dispatch(recipient_number) do |builder|
|
|
70
|
+
builder.media_id = video_id
|
|
71
|
+
builder.caption = "OPTIONAL - Image caption"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
warb_from_new.video.dispatch(recipient_number) do |builder|
|
|
75
|
+
builder.link = video_link
|
|
76
|
+
builder.caption = "OPTIONAL - Image caption"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# ################################################# #
|
|
80
|
+
# ============== Using Warb directly ============== #
|
|
81
|
+
# ################################################# #
|
|
82
|
+
|
|
83
|
+
Warb.video.dispatch(recipient_number, media_id: video_id)
|
|
84
|
+
Warb.video.dispatch(recipient_number, media_id: video_id, caption: "OPTIONAL - Image caption")
|
|
85
|
+
Warb.video.dispatch(recipient_number, link: video_link)
|
|
86
|
+
Warb.video.dispatch(recipient_number, link: video_link, caption: "OPTIONAL - Image caption")
|
|
87
|
+
|
|
88
|
+
Warb.video.dispatch(recipient_number) do |builder|
|
|
89
|
+
builder.media_id = video_id
|
|
90
|
+
builder.caption = "OPTIONAL - Image caption"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
Warb.video.dispatch(recipient_number) do |builder|
|
|
94
|
+
builder.link = video_link
|
|
95
|
+
builder.caption = "OPTIONAL - Image caption"
|
|
96
|
+
end
|
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,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,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.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
|