Skip to content

Commit 6e799a0

Browse files
authored
DEVX-8697: Messages API Updates for RCS and WhatsApp (#316)
* Implementing RCS channel in Messages API * Implementing Messaging update method * Adding code somments for update method * Adding rcs to CHANNELS hash in Message class * Bumping version and updating changelog
1 parent e5c41f1 commit 6e799a0

File tree

10 files changed

+312
-3
lines changed

10 files changed

+312
-3
lines changed

CHANGES.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# 7.27.0
2+
3+
* Updates Messages API implementation to add RCS channel as well as a new `PATCH` endpoint for RCS message revocation and WhatsApp Mark as Read features. [#316](https://github.com/Vonage/vonage-ruby-sdk/pull/316)
4+
* Updates to `talk`, `stream`, `input`, and `record` NCCOs in Voice API implementation. [#315](https://github.com/Vonage/vonage-ruby-sdk/pull/315)
5+
* Adds deprecation warnings to Meetings API and Proactive Connect API implementations, and updates code comments for Numbers API. [#314](https://github.com/Vonage/vonage-ruby-sdk/pull/314)
6+
7+
18
# 7.26.0
29

310
* Implements the Network Number Verification and Network SIM Swap APIs. [#313](https://github.com/Vonage/vonage-ruby-sdk/pull/313)

lib/vonage.rb

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module Vonage
1313
'http' => 'HTTP',
1414
'json' => 'JSON',
1515
'jwt' => 'JWT',
16+
'rcs' => 'RCS',
1617
'sip' => 'SIP',
1718
'sms' => 'SMS',
1819
'network_sim_swap' => 'NetworkSIMSwap',

lib/vonage/messaging.rb

+15-1
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,26 @@ class Messaging < Namespace
2525
# @option params [required, Hash] **message
2626
# The Vonage Message object to use for this message.
2727
#
28-
# @see https://developer.vonage.com/api/messages-olympus#SendMessage
28+
# @see https://developer.vonage.com/api/messages#SendMessage
2929
#
3030
def send(to:, from:, **message)
3131
request('/v1/messages', params: {to: to, from: from, **message}, type: Post)
3232
end
3333

34+
# Update a Message Object.
35+
#
36+
# @example
37+
# message = client.messaging.update(message_uuid: "aaaaaaaa-bbbb-4ccc-8ddd-0123456789ab", status: "read")
38+
#
39+
# @option params [required, String] :message_uuid. the UUID of the message to update.
40+
#
41+
# `:message_uuid` is always required. Other parameters will depend on the message channel and the specific action being performed.
42+
# @see https://developer.vonage.com/api/messages#UpdateMessage
43+
#
44+
def update(message_uuid:, **params)
45+
request("/v1/messages/#{message_uuid}", params: params, type: Patch)
46+
end
47+
3448
# Validate a JSON Web Token from a Messages API Webhook.
3549
#
3650
# @param [String, required] :token The JWT from the Webhook's Authorization header

lib/vonage/messaging/channels/rcs.rb

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# typed: true
2+
3+
module Vonage
4+
class Messaging::Channels::RCS < Messaging::Message
5+
MESSAGE_TYPES = ['text', 'image', 'video', 'file', 'custom']
6+
7+
attr_reader :data
8+
9+
def initialize(attributes = {})
10+
@type = attributes.fetch(:type, nil)
11+
@message = attributes.fetch(:message, nil)
12+
@opts = attributes.fetch(:opts, {})
13+
@data = {}
14+
15+
after_initialize!
16+
end
17+
18+
private
19+
20+
def build
21+
data[:channel] = 'rcs'
22+
super
23+
end
24+
25+
def verify_type
26+
raise ClientError.new("Invalid message type") unless MESSAGE_TYPES.include?(type)
27+
end
28+
29+
def verify_message
30+
case type
31+
when 'text'
32+
raise Vonage::ClientError.new("Invalid parameter type. `:message` must be a String") unless message.is_a? String
33+
when 'custom'
34+
raise Vonage::ClientError.new("Invalid parameter type. `:message` must be a Hash") unless message.is_a? Hash
35+
raise Vonage::ClientError.new("Invalid parameter content. `:message` must not be empty") if message.empty?
36+
else
37+
raise Vonage::ClientError.new("Invalid parameter type. `:message` must be a Hash") unless message.is_a? Hash
38+
raise Vonage::ClientError.new("Missing parameter. `:message` must contain a `:url` key") unless message[:url]
39+
end
40+
end
41+
end
42+
end

lib/vonage/messaging/message.rb

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class Messaging::Message
55
CHANNELS = {
66
sms: Vonage::Messaging::Channels::SMS,
77
mms: Vonage::Messaging::Channels::MMS,
8+
rcs: Vonage::Messaging::Channels::RCS,
89
whatsapp: Vonage::Messaging::Channels::WhatsApp,
910
messenger: Vonage::Messaging::Channels::Messenger,
1011
viber: Vonage::Messaging::Channels::Viber

lib/vonage/version.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# typed: strong
22

33
module Vonage
4-
VERSION = '7.26.0'
4+
VERSION = '7.27.0'
55
end
+226
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# typed: false
2+
3+
4+
class Vonage::Messaging::Channels::RCSTest < Vonage::Test
5+
def test_rcs_initialize
6+
message = Vonage::Messaging::Channels::RCS.new(type: 'text', message: 'Hello world!')
7+
8+
assert_kind_of Vonage::Messaging::Channels::RCS, message
9+
end
10+
11+
def test_rcs_text_message
12+
expected = {
13+
channel: 'rcs',
14+
message_type: 'text',
15+
text: 'Hello world!'
16+
}
17+
18+
message = Vonage::Messaging::Channels::RCS.new(
19+
type: 'text',
20+
message: 'Hello world!'
21+
)
22+
23+
assert_equal expected, message.data
24+
end
25+
26+
def test_rcs_text_message_wth_optional_parameters
27+
expected = {
28+
channel: 'rcs',
29+
message_type: 'text',
30+
text: 'Hello world!',
31+
ttl: 600,
32+
client_ref: "abc123",
33+
webhook_url: "https://example.com/status"
34+
}
35+
36+
message = Vonage::Messaging::Channels::RCS.new(
37+
type: 'text',
38+
message: 'Hello world!',
39+
opts: {
40+
ttl: 600,
41+
client_ref: "abc123",
42+
webhook_url: "https://example.com/status"
43+
}
44+
)
45+
46+
assert_equal expected, message.data
47+
end
48+
49+
def test_rcs_image_message
50+
expected = {
51+
channel: 'rcs',
52+
message_type: 'image',
53+
image: {
54+
url: 'https://example.com/image.jpg'
55+
}
56+
}
57+
58+
message = Vonage::Messaging::Channels::RCS.new(
59+
type: 'image',
60+
message: {
61+
url: 'https://example.com/image.jpg'
62+
}
63+
)
64+
65+
assert_equal expected, message.data
66+
end
67+
68+
def test_rcs_video_message
69+
expected = {
70+
channel: 'rcs',
71+
message_type: 'image',
72+
image: {
73+
url: 'https://example.com/video.webm'
74+
}
75+
}
76+
77+
message = Vonage::Messaging::Channels::RCS.new(
78+
type: 'image',
79+
message: {
80+
url: 'https://example.com/video.webm'
81+
}
82+
)
83+
84+
assert_equal expected, message.data
85+
end
86+
87+
def test_rcs_file_message
88+
expected = {
89+
channel: 'rcs',
90+
message_type: 'file',
91+
file: {
92+
url: 'https://example.com/file.pdf'
93+
}
94+
}
95+
96+
message = Vonage::Messaging::Channels::RCS.new(
97+
type: 'file',
98+
message: {
99+
url: 'https://example.com/file.pdf'
100+
}
101+
)
102+
103+
assert_equal expected, message.data
104+
end
105+
106+
def test_rcs_custom_message
107+
expected = {
108+
channel: 'rcs',
109+
message_type: 'custom',
110+
custom: {
111+
contentMessage: {
112+
text: 'Which ice-cream flavour do you prefer?',
113+
suggestions: [
114+
{
115+
reply: {
116+
text: 'Vanilla',
117+
postback: 'vanilla'
118+
}
119+
},
120+
{
121+
reply: {
122+
text: 'Chocolate',
123+
postback: 'chocolate'
124+
}
125+
}
126+
]
127+
}
128+
}
129+
}
130+
131+
message = Vonage::Messaging::Channels::RCS.new(
132+
type: 'custom',
133+
message: {
134+
contentMessage: {
135+
text: 'Which ice-cream flavour do you prefer?',
136+
suggestions: [
137+
{
138+
reply: {
139+
text: 'Vanilla',
140+
postback: 'vanilla'
141+
}
142+
},
143+
{
144+
reply: {
145+
text: 'Chocolate',
146+
postback: 'chocolate'
147+
}
148+
}
149+
]
150+
}
151+
}
152+
)
153+
154+
assert_equal expected, message.data
155+
end
156+
157+
def test_rcs_invalid_message_type
158+
exception = assert_raises { Vonage::Messaging::Channels::RCS.new(type: 'invalid', message: 'Hello world!') }
159+
160+
assert_instance_of Vonage::ClientError, exception
161+
assert_match "Invalid message type", exception.message
162+
end
163+
164+
def test_rcs_text_message_invalid_type
165+
exception = assert_raises { Vonage::Messaging::Channels::RCS.new(type: 'text', message: 123) }
166+
167+
assert_instance_of Vonage::ClientError, exception
168+
assert_match "Invalid parameter type. `:message` must be a String", exception.message
169+
end
170+
171+
def test_rcs_image_message_invalid_type
172+
exception = assert_raises { Vonage::Messaging::Channels::RCS.new(type: 'image', message: 'https://example.com/image.jpg') }
173+
174+
assert_instance_of Vonage::ClientError, exception
175+
assert_match "Invalid parameter type. `:message` must be a Hash", exception.message
176+
end
177+
178+
def test_rcs_image_message_missing_url
179+
exception = assert_raises { Vonage::Messaging::Channels::RCS.new(type: 'image', message: {}) }
180+
181+
assert_instance_of Vonage::ClientError, exception
182+
assert_match "Missing parameter. `:message` must contain a `:url` key", exception.message
183+
end
184+
185+
def test_rcs_video_message_invalid_type
186+
exception = assert_raises { Vonage::Messaging::Channels::RCS.new(type: 'video', message: 'https://example.com/video.webm') }
187+
188+
assert_instance_of Vonage::ClientError, exception
189+
assert_match "Invalid parameter type. `:message` must be a Hash", exception.message
190+
end
191+
192+
def test_rcs_video_message_missing_url
193+
exception = assert_raises { Vonage::Messaging::Channels::RCS.new(type: 'video', message: {}) }
194+
195+
assert_instance_of Vonage::ClientError, exception
196+
assert_match "Missing parameter. `:message` must contain a `:url` key", exception.message
197+
end
198+
199+
def test_rcs_file_message_invalid_type
200+
exception = assert_raises { Vonage::Messaging::Channels::RCS.new(type: 'file', message: 'https://example.com/file.pdf') }
201+
202+
assert_instance_of Vonage::ClientError, exception
203+
assert_match "Invalid parameter type. `:message` must be a Hash", exception.message
204+
end
205+
206+
def test_rcs_file_message_missing_url
207+
exception = assert_raises { Vonage::Messaging::Channels::RCS.new(type: 'file', message: {}) }
208+
209+
assert_instance_of Vonage::ClientError, exception
210+
assert_match "Missing parameter. `:message` must contain a `:url` key", exception.message
211+
end
212+
213+
def test_rcs_custom_message_invalid_type
214+
exception = assert_raises { Vonage::Messaging::Channels::RCS.new(type: 'custom', message: 'Hello world!') }
215+
216+
assert_instance_of Vonage::ClientError, exception
217+
assert_match "Invalid parameter type. `:message` must be a Hash", exception.message
218+
end
219+
220+
def test_rcs_custom_message_with_empty_message_hash
221+
exception = assert_raises { Vonage::Messaging::Channels::RCS.new(type: 'custom', message: {}) }
222+
223+
assert_instance_of Vonage::ClientError, exception
224+
assert_match "Invalid parameter content. `:message` must not be empty", exception.message
225+
end
226+
end

test/vonage/messaging/channels/whats_app_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

44
class Vonage::Messaging::Channels::WhatsAppTest < Vonage::Test
5-
def test_messenger_initialize
5+
def test_whats_app_initialize
66
whatsapp = Vonage::Messaging::Channels::WhatsApp.new(type: 'text', message: 'Hello world!')
77

88
assert_kind_of Vonage::Messaging::Channels::WhatsApp, whatsapp

test/vonage/messaging_test.rb

+14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ def messaging
66
Vonage::Messaging.new(config)
77
end
88

9+
def geo_specific_messaging_host
10+
'api-eu.vonage.com'
11+
end
12+
13+
def geo_specific_messaging
14+
Vonage::Messaging.new(config.merge(api_host: geo_specific_messaging_host))
15+
end
16+
917
def messaging_uri
1018
'https://api.nexmo.com/v1/messages'
1119
end
@@ -65,4 +73,10 @@ def test_verify_webhook_token_method_with_invalid_secret
6573
def test_verify_webhook_token_method_with_no_token
6674
assert_raises(ArgumentError) { messaging.verify_webhook_token }
6775
end
76+
77+
def test_update_method
78+
stub_request(:patch, 'https://' + geo_specific_messaging_host + '/v1/messages/' + message_uuid).with(request(body: {status: 'read'})).to_return(response)
79+
80+
assert_kind_of Vonage::Response, geo_specific_messaging.update(message_uuid: message_uuid, status: 'read')
81+
end
6882
end

test/vonage/test.rb

+4
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,10 @@ def meetings_id
406406
"MEET-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
407407
end
408408

409+
def message_uuid
410+
"aaaaaaaa-bbbb-4ccc-8ddd-0123456789ab"
411+
end
412+
409413
def video_id
410414
'VIDEO-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
411415
end

0 commit comments

Comments
 (0)