cloud-waba-ruby-client 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +9 -1
- data/cloud-waba-ruby-client.gemspec +1 -1
- data/lib/api/messages/service.rb +77 -9
- data/lib/api/templates/service.rb +23 -4
- data/lib/cloud_waba/client.rb +8 -0
- data/lib/cloud_waba/errors/bad_request.rb +9 -0
- data/lib/cloud_waba/errors/missing_parameter.rb +9 -0
- data/lib/cloud_waba/errors/unauthorized.rb +9 -0
- data/lib/cloud_waba/models/media/response.rb +48 -0
- data/lib/cloud_waba/utils.rb +30 -4
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 776fe9551683b144357021a087daf8be4600e8bed893552017ded5d0ddbf9306
|
4
|
+
data.tar.gz: 9f6118a9123f470b303a255ba782a7db3349abfcc649c4d391f04c4e4aeef473
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 849442cf4206504c78a3552d75eb87c27c3a9e0b68ac67e28ff4644706cc3d3048d9a634aadbc7dc4abf2fa0566848165e800ce27275adb70ab359f706ecd395
|
7
|
+
data.tar.gz: da26c3bc79ef14949ae2aba44816685a9e10a02bbb49f52892dc72ee9608a117131ccffdf55ce0076dc4f9eae1637a3319c22e3664e68101258650626f2b6d84
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@ Ruby wrapper for [Cloud WhatsApp Business API](https://developers.facebook.com/d
|
|
7
7
|
Add following line to your Gemfile:
|
8
8
|
|
9
9
|
```ruby
|
10
|
-
gem 'cloud-waba-ruby-client', '~> 0.0.
|
10
|
+
gem 'cloud-waba-ruby-client', '~> 0.0.5'
|
11
11
|
```
|
12
12
|
|
13
13
|
then run
|
@@ -134,6 +134,14 @@ phone_1 = ::CloudWaba::Models::Messages::ContactPhone.new(type: ::CloudWaba::Mod
|
|
134
134
|
contacts = [::CloudWaba::Models::Messages::Contact.new(name: name, phones: [phone_1])]
|
135
135
|
client.messages.send_contact(contacts: contacts,recipient: "+201XXXXXXXXX")
|
136
136
|
```
|
137
|
+
|
138
|
+
### Sending reaction on a message
|
139
|
+
```ruby
|
140
|
+
require "cloud_waba/client"
|
141
|
+
|
142
|
+
client = CloudWaba::Client.new
|
143
|
+
client.messages.send_reaction(recipient: "+201XXXXXXXXX", emoji: "💙", reply_message_id: "wamid.HBgMMjAxMjAxMzIyMzMxFQIAEZgSQTU5QkExMUUyQlRCNTU1NTVEAA==")
|
144
|
+
```
|
137
145
|
<!-- ### Sending template with header, body, footer and buttons
|
138
146
|
|
139
147
|
### Sending template with header, body, footer and buttons (variables)
|
data/lib/api/messages/service.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
4
|
+
require 'pry'
|
5
5
|
|
6
6
|
module API
|
7
7
|
module Messages
|
@@ -37,7 +37,8 @@ module API
|
|
37
37
|
|
38
38
|
payload["context"] = { "message_id": reply_message_id } unless reply_message_id.nil?
|
39
39
|
|
40
|
-
response = http_client.post(body: payload, headers: {})
|
40
|
+
response = with_error_handling { http_client.post(body: payload, headers: {}) }
|
41
|
+
|
41
42
|
parsed_response = JSON.parse(response.body.to_s)
|
42
43
|
::CloudWaba::Models::Messages::Response.parse(hash: parsed_response)
|
43
44
|
end
|
@@ -58,7 +59,7 @@ module API
|
|
58
59
|
payload["image"] = { link: link, caption: caption }
|
59
60
|
payload["context"] = { "message_id": reply_message_id } unless reply_message_id.nil?
|
60
61
|
|
61
|
-
response = http_client.post(body: payload, headers: {})
|
62
|
+
response = with_error_handling { http_client.post(body: payload, headers: {}) }
|
62
63
|
parsed_response = JSON.parse(response.body.to_s)
|
63
64
|
::CloudWaba::Models::Messages::Response.parse(hash: parsed_response)
|
64
65
|
end
|
@@ -79,7 +80,7 @@ module API
|
|
79
80
|
payload["audio"] = { link: link }
|
80
81
|
payload["context"] = { "message_id": reply_message_id } unless reply_message_id.nil?
|
81
82
|
|
82
|
-
response = http_client.post(body: payload, headers: {})
|
83
|
+
response = with_error_handling { http_client.post(body: payload, headers: {}) }
|
83
84
|
parsed_response = JSON.parse(response.body.to_s)
|
84
85
|
::CloudWaba::Models::Messages::Response.parse(hash: parsed_response)
|
85
86
|
end
|
@@ -100,7 +101,7 @@ module API
|
|
100
101
|
payload["video"] = { link: link, caption: caption }
|
101
102
|
payload["context"] = { "message_id": reply_message_id } unless reply_message_id.nil?
|
102
103
|
|
103
|
-
response = http_client.post(body: payload, headers: {})
|
104
|
+
response = with_error_handling { http_client.post(body: payload, headers: {}) }
|
104
105
|
parsed_response = JSON.parse(response.body.to_s)
|
105
106
|
::CloudWaba::Models::Messages::Response.parse(hash: parsed_response)
|
106
107
|
end
|
@@ -121,7 +122,7 @@ module API
|
|
121
122
|
payload["document"] = { link: link, caption: caption }
|
122
123
|
payload["context"] = { "message_id": reply_message_id } unless reply_message_id.nil?
|
123
124
|
|
124
|
-
response = http_client.post(body: payload, headers: {})
|
125
|
+
response = with_error_handling { http_client.post(body: payload, headers: {}) }
|
125
126
|
parsed_response = JSON.parse(response.body.to_s)
|
126
127
|
::CloudWaba::Models::Messages::Response.parse(hash: parsed_response)
|
127
128
|
end
|
@@ -147,7 +148,7 @@ module API
|
|
147
148
|
}
|
148
149
|
payload["context"] = { "message_id": reply_message_id } unless reply_message_id.nil?
|
149
150
|
|
150
|
-
response = http_client.post(body: payload, headers: {})
|
151
|
+
response = with_error_handling { http_client.post(body: payload, headers: {}) }
|
151
152
|
parsed_response = JSON.parse(response.body.to_s)
|
152
153
|
::CloudWaba::Models::Messages::Response.parse(hash: parsed_response)
|
153
154
|
end
|
@@ -168,11 +169,49 @@ module API
|
|
168
169
|
payload["contacts"] = contacts.map(&:serialize)
|
169
170
|
payload["context"] = { "message_id": reply_message_id } unless reply_message_id.nil?
|
170
171
|
|
171
|
-
response = http_client.post(body: payload, headers: {})
|
172
|
+
response = with_error_handling { http_client.post(body: payload, headers: {}) }
|
173
|
+
parsed_response = JSON.parse(response.body.to_s)
|
174
|
+
::CloudWaba::Models::Messages::Response.parse(hash: parsed_response)
|
175
|
+
end
|
176
|
+
|
177
|
+
# curl -X POST \
|
178
|
+
# 'https://graph.facebook.com/v18.0/FROM_PHONE_NUMBER_ID/messages' \
|
179
|
+
# -H 'Authorization: Bearer ACCESS_TOKEN' \
|
180
|
+
# -H 'Content-Type: application/json' \
|
181
|
+
# -d '{
|
182
|
+
# "messaging_product": "whatsapp",
|
183
|
+
# "recipient_type": "individual",
|
184
|
+
# "to": "PHONE_NUMBER",
|
185
|
+
# "type": "reaction",
|
186
|
+
# "reaction": {
|
187
|
+
# "message_id": "wamid.HBgLM...",
|
188
|
+
# "emoji": "\uD83D\uDE00"
|
189
|
+
# }
|
190
|
+
# }'
|
191
|
+
sig do
|
192
|
+
params(recipient: ::String, emoji: ::String, reply_message_id: ::String).returns(::CloudWaba::Models::Messages::Response)
|
193
|
+
end
|
194
|
+
def send_reaction(recipient:, emoji:, reply_message_id: nil)
|
195
|
+
reaction_type = "reaction"
|
196
|
+
|
197
|
+
payload = {
|
198
|
+
"messaging_product": MESSAGING_PRODUCT,
|
199
|
+
"recipient_type": RECIPIENT_TYPE,
|
200
|
+
"to": recipient,
|
201
|
+
"type": reaction_type,
|
202
|
+
}
|
203
|
+
|
204
|
+
payload["reaction"] = {
|
205
|
+
"message_id": reply_message_id,
|
206
|
+
"emoji": emoji
|
207
|
+
}
|
208
|
+
|
209
|
+
response = with_error_handling { http_client.post(body: payload, headers: {}) }
|
172
210
|
parsed_response = JSON.parse(response.body.to_s)
|
173
211
|
::CloudWaba::Models::Messages::Response.parse(hash: parsed_response)
|
174
212
|
end
|
175
213
|
|
214
|
+
|
176
215
|
sig do
|
177
216
|
params(
|
178
217
|
recipient: ::String,
|
@@ -198,11 +237,21 @@ module API
|
|
198
237
|
}
|
199
238
|
}
|
200
239
|
|
201
|
-
response = http_client.post(body: payload, headers: {})
|
240
|
+
response = with_error_handling { http_client.post(body: payload, headers: {}) }
|
202
241
|
parsed_response = JSON.parse(response.body.to_s)
|
203
242
|
::CloudWaba::Models::Messages::Response.parse(hash: parsed_response)
|
204
243
|
end
|
205
244
|
|
245
|
+
sig do
|
246
|
+
params(media_id: ::String).returns(::CloudWaba::Models::Media::Response)
|
247
|
+
end
|
248
|
+
def fetch_media_url(media_id:)
|
249
|
+
url = "#{@config.base_url}/#{@config.api_version}/#{media_id}"
|
250
|
+
response = with_error_handling { http_client.get(url) }
|
251
|
+
parsed_response = JSON.parse(response.body.to_s)
|
252
|
+
::CloudWaba::Models::Media::Response.parse(hash: parsed_response)
|
253
|
+
end
|
254
|
+
|
206
255
|
private
|
207
256
|
|
208
257
|
def http_client
|
@@ -212,6 +261,25 @@ module API
|
|
212
261
|
def messages_endpoint
|
213
262
|
"#{@config.base_url}/#{@config.api_version}/#{@config.phone_number_id}/messages"
|
214
263
|
end
|
264
|
+
|
265
|
+
def with_error_handling
|
266
|
+
return unless block_given?
|
267
|
+
|
268
|
+
response = yield
|
269
|
+
parsed_response = JSON.parse(response.body.to_s)
|
270
|
+
error_message = parsed_response.dig("error", "message")
|
271
|
+
|
272
|
+
case response.code
|
273
|
+
when 400
|
274
|
+
raise ::CloudWaba::Errors::BadRequest, error_message
|
275
|
+
when 401
|
276
|
+
raise ::CloudWaba::Errors::Unauthorized, error_message
|
277
|
+
else
|
278
|
+
# Success
|
279
|
+
end
|
280
|
+
|
281
|
+
response
|
282
|
+
end
|
215
283
|
end
|
216
284
|
end
|
217
285
|
end
|
@@ -21,7 +21,7 @@ module API
|
|
21
21
|
end
|
22
22
|
def list(limit: 20)
|
23
23
|
fields = "id,name,category,language,status"
|
24
|
-
response = templates_client.get(params: { fields: fields, limit: limit })
|
24
|
+
response = with_error_handling { templates_client.get(params: { fields: fields, limit: limit }) }
|
25
25
|
|
26
26
|
parsed_response = JSON.parse(response.body.to_s)
|
27
27
|
templates = parsed_response["data"].map{|hash| ::CloudWaba::Models::Templates::Response.parse(template_hash: hash)}
|
@@ -47,7 +47,7 @@ module API
|
|
47
47
|
"components": components.map(&:serialize)
|
48
48
|
}
|
49
49
|
|
50
|
-
response = templates_client.post(body: payload)
|
50
|
+
response = with_error_handling { templates_client.post(body: payload) }
|
51
51
|
::CloudWaba::Models::Templates::Response.parse(response: response)
|
52
52
|
end
|
53
53
|
|
@@ -64,7 +64,7 @@ module API
|
|
64
64
|
"category": category.serialize,
|
65
65
|
"components": components.map(&:serialize)
|
66
66
|
}
|
67
|
-
response = client.post(body: payload)
|
67
|
+
response = with_error_handling { client.post(body: payload) }
|
68
68
|
parsed_response = JSON.parse(response.body.to_s)
|
69
69
|
|
70
70
|
parsed_response["success"] || false
|
@@ -80,7 +80,7 @@ module API
|
|
80
80
|
params = { name: name }
|
81
81
|
params[:hsm_id] = template_id unless template_id.nil?
|
82
82
|
|
83
|
-
response = templates_client.delete(params: params)
|
83
|
+
response = with_error_handling { templates_client.delete(params: params) }
|
84
84
|
parsed_response = JSON.parse(response.body.to_s)
|
85
85
|
|
86
86
|
parsed_response["success"] || false
|
@@ -103,6 +103,25 @@ module API
|
|
103
103
|
def template_endpoint(template_id:)
|
104
104
|
"#{@config.base_url}/#{@config.api_version}/#{template_id}"
|
105
105
|
end
|
106
|
+
|
107
|
+
def with_error_handling
|
108
|
+
return unless block_given?
|
109
|
+
|
110
|
+
response = yield
|
111
|
+
parsed_response = JSON.parse(response.body.to_s)
|
112
|
+
error_message = parsed_response.dig("error", "message")
|
113
|
+
|
114
|
+
case response.code
|
115
|
+
when 400
|
116
|
+
raise ::CloudWaba::Errors::BadRequest, error_message
|
117
|
+
when 401
|
118
|
+
raise ::CloudWaba::Errors::Unauthorized, error_message
|
119
|
+
else
|
120
|
+
# Success
|
121
|
+
end
|
122
|
+
|
123
|
+
response
|
124
|
+
end
|
106
125
|
end
|
107
126
|
end
|
108
127
|
end
|
data/lib/cloud_waba/client.rb
CHANGED
@@ -10,6 +10,7 @@ require_relative "models/enums/templates/component_type"
|
|
10
10
|
require_relative "models/enums/templates/button_type"
|
11
11
|
require_relative "models/enums/templates/format"
|
12
12
|
require_relative "models/enums/contact_phone_type"
|
13
|
+
|
13
14
|
# Models
|
14
15
|
require_relative "models/config"
|
15
16
|
require_relative "models/contact"
|
@@ -17,6 +18,7 @@ require_relative "models/messages/response"
|
|
17
18
|
require_relative "models/messages/contact_name"
|
18
19
|
require_relative "models/messages/contact_phone"
|
19
20
|
require_relative "models/messages/contact"
|
21
|
+
require_relative "models/media/response"
|
20
22
|
|
21
23
|
require_relative "models/templates/example"
|
22
24
|
require_relative "models/templates/component"
|
@@ -35,6 +37,12 @@ require_relative "models/templates/buttons_component"
|
|
35
37
|
require_relative "models/templates/message_template"
|
36
38
|
require_relative "models/templates/response"
|
37
39
|
require_relative "models/templates/list"
|
40
|
+
|
41
|
+
# Errors
|
42
|
+
require_relative "errors/unauthorized"
|
43
|
+
require_relative "errors/bad_request"
|
44
|
+
require_relative "errors/missing_parameter"
|
45
|
+
|
38
46
|
# Helpers
|
39
47
|
require_relative "utils"
|
40
48
|
require_relative "http_client"
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# require 'pry'
|
5
|
+
|
6
|
+
module CloudWaba
|
7
|
+
module Models
|
8
|
+
module Media
|
9
|
+
class Response < T::Struct
|
10
|
+
extend ::T::Sig
|
11
|
+
extend ::T::Helpers
|
12
|
+
##
|
13
|
+
# {
|
14
|
+
# "messaging_product": "whatsapp",
|
15
|
+
# "url": "<URL>",
|
16
|
+
# "mime_type": "<MIME_TYPE>",
|
17
|
+
# "sha256": "<HASH>",
|
18
|
+
# "file_size": "<FILE_SIZE>",
|
19
|
+
# "id": "<MEDIA_ID>"
|
20
|
+
# }
|
21
|
+
prop :messaging_product, ::CloudWaba::Models::Enums::MessagingProduct
|
22
|
+
prop :url, ::String
|
23
|
+
prop :mime_type, ::String
|
24
|
+
prop :sha256, ::String
|
25
|
+
prop :file_size, ::Integer
|
26
|
+
prop :id, ::String
|
27
|
+
|
28
|
+
sig { params(hash: ::T::Hash[::T.untyped, ::T.untyped]).returns(::CloudWaba::Models::Media::Response) }
|
29
|
+
def self.parse(hash:)
|
30
|
+
id = hash["id"]
|
31
|
+
url = hash["url"]
|
32
|
+
mime_type = hash["mime_type"]
|
33
|
+
sha256 = hash["sha256"]
|
34
|
+
file_size = hash["file_size"]
|
35
|
+
|
36
|
+
self.new(
|
37
|
+
messaging_product: ::CloudWaba::Models::Enums::MessagingProduct::WhatsApp,
|
38
|
+
url: url,
|
39
|
+
mime_type: mime_type,
|
40
|
+
sha256: sha256,
|
41
|
+
file_size: file_size,
|
42
|
+
id: id,
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/cloud_waba/utils.rb
CHANGED
@@ -18,7 +18,6 @@ module CloudWaba
|
|
18
18
|
end
|
19
19
|
def self.import_config(app_id:, app_secret:, phone_number_id:, business_account_id:, access_token:, api_version:)
|
20
20
|
Dotenv.load
|
21
|
-
validate_config!
|
22
21
|
|
23
22
|
base_url = ENV.fetch("WA_BASE_URL", "https://graph.facebook.com")
|
24
23
|
app_id = app_id || ENV.fetch("M4D_APP_ID", "")
|
@@ -28,6 +27,14 @@ module CloudWaba
|
|
28
27
|
access_token = access_token || ENV.fetch("CLOUD_API_ACCESS_TOKEN", "")
|
29
28
|
api_version = api_version || ENV.fetch("CLOUD_API_VERSION", "v16.0")
|
30
29
|
|
30
|
+
validate_config!(
|
31
|
+
app_id: app_id,
|
32
|
+
app_secret: app_secret,
|
33
|
+
phone_number_id: phone_number_id,
|
34
|
+
business_account_id: business_account_id,
|
35
|
+
access_token: access_token
|
36
|
+
)
|
37
|
+
|
31
38
|
::CloudWaba::Models::Config.new(
|
32
39
|
base_url: base_url,
|
33
40
|
app_id: app_id,
|
@@ -41,9 +48,28 @@ module CloudWaba
|
|
41
48
|
|
42
49
|
private
|
43
50
|
|
44
|
-
sig {
|
45
|
-
|
46
|
-
|
51
|
+
sig { params(
|
52
|
+
app_id: ::T.nilable(::String),
|
53
|
+
app_secret: ::T.nilable(::String),
|
54
|
+
phone_number_id: ::T.nilable(::String),
|
55
|
+
business_account_id: ::T.nilable(::String),
|
56
|
+
access_token: ::T.nilable(::String)).void }
|
57
|
+
def self.validate_config!(app_id:, app_secret:, phone_number_id:, business_account_id:, access_token:)
|
58
|
+
error_message = nil
|
59
|
+
|
60
|
+
if app_id.nil? || app_id.empty?
|
61
|
+
error_message = "app_id parameter is missing"
|
62
|
+
elsif app_secret.nil? || app_secret.empty?
|
63
|
+
error_message = "app_secret parameter is missing"
|
64
|
+
elsif phone_number_id.nil? || phone_number_id.empty?
|
65
|
+
error_message = "phone_number_id parameter is missing"
|
66
|
+
elsif business_account_id.nil? || business_account_id.empty?
|
67
|
+
error_message = "business_account_id parameter is missing"
|
68
|
+
elsif access_token.nil? || access_token.empty?
|
69
|
+
error_message = "access_token parameter is missing"
|
70
|
+
end
|
71
|
+
|
72
|
+
raise ::CloudWaba::Errors::MissingParameter, error_message unless error_message.nil?
|
47
73
|
end
|
48
74
|
end
|
49
75
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloud-waba-ruby-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ahmed Bassell
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dotenv
|
@@ -112,6 +112,9 @@ files:
|
|
112
112
|
- lib/api/messages/service.rb
|
113
113
|
- lib/api/templates/service.rb
|
114
114
|
- lib/cloud_waba/client.rb
|
115
|
+
- lib/cloud_waba/errors/bad_request.rb
|
116
|
+
- lib/cloud_waba/errors/missing_parameter.rb
|
117
|
+
- lib/cloud_waba/errors/unauthorized.rb
|
115
118
|
- lib/cloud_waba/http_client.rb
|
116
119
|
- lib/cloud_waba/models/config.rb
|
117
120
|
- lib/cloud_waba/models/contact.rb
|
@@ -121,6 +124,7 @@ files:
|
|
121
124
|
- lib/cloud_waba/models/enums/templates/category.rb
|
122
125
|
- lib/cloud_waba/models/enums/templates/component_type.rb
|
123
126
|
- lib/cloud_waba/models/enums/templates/format.rb
|
127
|
+
- lib/cloud_waba/models/media/response.rb
|
124
128
|
- lib/cloud_waba/models/messages/contact.rb
|
125
129
|
- lib/cloud_waba/models/messages/contact_name.rb
|
126
130
|
- lib/cloud_waba/models/messages/contact_phone.rb
|