Skip to content

Commit 4a27754

Browse files
committed
fix conflict
2 parents bfdbcd1 + 0cde800 commit 4a27754

File tree

12 files changed

+338
-7
lines changed

12 files changed

+338
-7
lines changed

messages/CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 1.2.0
2+
- Add RCS channel support
3+
- Add methods to revoke an RCS message and mark a WhatsApp message as read
4+
15
# 1.1.1
26
- Update minimum dependency version
37

messages/README.md

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ This message can now be sent with
2626
vonage_client.messages.send(message)
2727
```
2828

29-
All possible message types from every message channel have their own message model. They are named following this rule: {Channel}{MessageType}, e.g. `Sms`, `MmsImage`, `MessengerAudio`, `WhatsappSticker`, `ViberVideo`, etc.
29+
All possible message types from every message channel have their own message model. They are named following this rule: {Channel}{MessageType}, e.g. `Sms`, `MmsImage`, `RcsFile`, `MessengerAudio`, `WhatsappSticker`, `ViberVideo`, etc.
3030

3131
The different message models are listed at the bottom of the page.
3232

@@ -64,14 +64,47 @@ message = Sms(
6464
vonage_client.messages.send(message)
6565
```
6666

67+
### Mark a WhatsApp Message as Read
68+
69+
Note: to use this method, update the `api_host` attribute of the `vonage_http_client.HttpClientOptions` object to the API endpoint corresponding to the region where the WhatsApp number is hosted.
70+
71+
For example, to use the EU API endpoint, set the `api_host` attribute to 'api-eu.vonage.com'.
72+
73+
```python
74+
from vonage import Vonage, Auth, HttpClientOptions
75+
76+
auth = Auth(application_id='MY-APP-ID', private_key='MY-PRIVATE-KEY')
77+
options = HttpClientOptions(api_host='api-eu.vonage.com')
78+
79+
vonage_client = Vonage(auth, options)
80+
vonage_client.messages.mark_whatsapp_message_read('MESSAGE_UUID')
81+
```
82+
83+
### Revoke an RCS Message
84+
85+
Note: as above, to use this method you need to update the `api_host` attribute of the `vonage_http_client.HttpClientOptions` object to the API endpoint corresponding to the region where the WhatsApp number is hosted.
86+
87+
For example, to use the EU API endpoint, set the `api_host` attribute to 'api-eu.vonage.com'.
88+
89+
```python
90+
from vonage import Vonage, Auth, HttpClientOptions
91+
92+
auth = Auth(application_id='MY-APP-ID', private_key='MY-PRIVATE-KEY')
93+
options = HttpClientOptions(api_host='api-eu.vonage.com')
94+
95+
vonage_client = Vonage(auth, options)
96+
vonage_client.messages.revoke_rcs_message('MESSAGE_UUID')
97+
```
98+
6799
## Message Models
68100

69101
To send a message, instantiate a message model of the correct type as described above. This is a list of message models that can be used:
70102

71103
```
72104
Sms
73105
MmsImage, MmsVcard, MmsAudio, MmsVideo
106+
RcsText, RcsImage, RcsVideo, RcsFile, RcsCustom
74107
WhatsappText, WhatsappImage, WhatsappAudio, WhatsappVideo, WhatsappFile, WhatsappTemplate, WhatsappSticker, WhatsappCustom
75108
MessengerText, MessengerImage, MessengerAudio, MessengerVideo, MessengerFile
76109
ViberText, ViberImage, ViberVideo, ViberFile
77-
```
110+
```

messages/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
[project]
22
name = 'vonage-messages'
3-
version = '1.1.1'
3+
version = '1.2.0'
44
description = 'Vonage messages package'
55
readme = "README.md"
66
authors = [{ name = "Vonage", email = "[email protected]" }]
77
requires-python = ">=3.8"
88
dependencies = [
9-
"vonage-http-client>=1.3.1",
9+
"vonage-http-client>=1.4.0",
1010
"vonage-utils>=1.1.1",
1111
"pydantic>=2.7.1",
1212
]

messages/src/vonage_messages/messages.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,43 @@ def send(self, message: BaseMessage) -> SendMessageResponse:
4444
message.model_dump(by_alias=True, exclude_none=True) or message,
4545
)
4646
return SendMessageResponse(**response)
47+
48+
@validate_call
49+
def mark_whatsapp_message_read(self, message_uuid: str) -> None:
50+
"""Mark a WhatsApp message as read.
51+
52+
Note: to use this method, update the `api_host` attribute of the
53+
`vonage_http_client.HttpClientOptions` object to the API endpoint
54+
corresponding to the region where the WhatsApp number is hosted.
55+
56+
For example, to use the EU API endpoint, set the `api_host`
57+
attribute to 'api-eu.vonage.com'.
58+
59+
Args:
60+
message_uuid (str): The unique identifier of the WhatsApp message to mark as read.
61+
"""
62+
self._http_client.patch(
63+
self._http_client.api_host,
64+
f'/v1/messages/{message_uuid}',
65+
{'status': 'read'},
66+
)
67+
68+
@validate_call
69+
def revoke_rcs_message(self, message_uuid: str) -> None:
70+
"""Revoke an RCS message.
71+
72+
Note: to use this method, update the `api_host` attribute of the
73+
`vonage_http_client.HttpClientOptions` object to the API endpoint
74+
corresponding to the region where the RCS number is hosted.
75+
76+
For example, to use the EU API endpoint, set the `api_host`
77+
attribute to 'api-eu.vonage.com'.
78+
79+
Args:
80+
message_uuid (str): The unique identifier of the RCS message to revoke.
81+
"""
82+
self._http_client.patch(
83+
self._http_client.api_host,
84+
f'/v1/messages/{message_uuid}',
85+
{'status': 'revoked'},
86+
)

messages/src/vonage_messages/models/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
MessengerVideo,
1111
)
1212
from .mms import MmsAudio, MmsImage, MmsResource, MmsVcard, MmsVideo
13+
from .rcs import RcsCustom, RcsFile, RcsImage, RcsResource, RcsText, RcsVideo
1314
from .sms import Sms, SmsOptions
1415
from .viber import (
1516
ViberAction,
@@ -62,6 +63,12 @@
6263
'MmsResource',
6364
'MmsVcard',
6465
'MmsVideo',
66+
'RcsCustom',
67+
'RcsFile',
68+
'RcsImage',
69+
'RcsResource',
70+
'RcsText',
71+
'RcsVideo',
6572
'Sms',
6673
'SmsOptions',
6774
'ViberAction',

messages/src/vonage_messages/models/enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class MessageType(str, Enum):
1616
class ChannelType(str, Enum):
1717
SMS = 'sms'
1818
MMS = 'mms'
19+
RCS = 'rcs'
1920
WHATSAPP = 'whatsapp'
2021
MESSENGER = 'messenger'
2122
VIBER = 'viber_service'
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from typing import Optional
2+
3+
from pydantic import BaseModel, Field
4+
from vonage_utils.types import PhoneNumber
5+
6+
from .base_message import BaseMessage
7+
from .enums import ChannelType, MessageType
8+
9+
10+
class RcsResource(BaseModel):
11+
url: str
12+
13+
14+
class BaseRcs(BaseMessage):
15+
to: PhoneNumber
16+
from_: str = Field(..., serialization_alias='from', pattern='^[a-zA-Z0-9]+$')
17+
ttl: Optional[int] = Field(None, ge=300, le=259200)
18+
channel: ChannelType = ChannelType.RCS
19+
20+
21+
class RcsText(BaseRcs):
22+
text: str = Field(..., min_length=1, max_length=3072)
23+
message_type: MessageType = MessageType.TEXT
24+
25+
26+
class RcsImage(BaseRcs):
27+
image: RcsResource
28+
message_type: MessageType = MessageType.IMAGE
29+
30+
31+
class RcsVideo(BaseRcs):
32+
video: RcsResource
33+
message_type: MessageType = MessageType.VIDEO
34+
35+
36+
class RcsFile(BaseRcs):
37+
file: RcsResource
38+
message_type: MessageType = MessageType.FILE
39+
40+
41+
class RcsCustom(BaseRcs):
42+
custom: dict
43+
message_type: MessageType = MessageType.CUSTOM

messages/tests/data/not_found.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "https://developer.vonage.com/api-errors#not-found",
3+
"title": "Not Found",
4+
"detail": "Message with ID asdf not found",
5+
"instance": "617431f2-06b7-4798-af36-1b8151df8359"
6+
}

messages/tests/test_messages.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import responses
44
from pytest import raises
55
from vonage_http_client.errors import HttpRequestError
6-
from vonage_http_client.http_client import HttpClient
6+
from vonage_http_client.http_client import HttpClient, HttpClientOptions
77
from vonage_messages.messages import Messages
88
from vonage_messages.models import Sms
99
from vonage_messages.models.messenger import (
@@ -81,3 +81,67 @@ def test_http_client_property():
8181
http_client = HttpClient(get_mock_jwt_auth())
8282
messages = Messages(http_client)
8383
assert messages.http_client == http_client
84+
85+
86+
@responses.activate
87+
def test_mark_whatsapp_message_read():
88+
responses.add(
89+
responses.PATCH,
90+
'https://api-eu.vonage.com/v1/messages/asdf',
91+
)
92+
messages = Messages(
93+
HttpClient(get_mock_jwt_auth(), HttpClientOptions(api_host='api-eu.vonage.com'))
94+
)
95+
messages.http_client.http_client_options.api_host = 'api-eu.vonage.com'
96+
messages.mark_whatsapp_message_read('asdf')
97+
98+
99+
@responses.activate
100+
def test_mark_whatsapp_message_read_not_found():
101+
build_response(
102+
path,
103+
'PATCH',
104+
'https://api-eu.vonage.com/v1/messages/asdf',
105+
'not_found.json',
106+
404,
107+
)
108+
messages = Messages(
109+
HttpClient(get_mock_jwt_auth(), HttpClientOptions(api_host='api-eu.vonage.com'))
110+
)
111+
with raises(HttpRequestError) as e:
112+
messages.mark_whatsapp_message_read('asdf')
113+
114+
assert e.value.response.status_code == 404
115+
assert e.value.response.json()['title'] == 'Not Found'
116+
117+
118+
@responses.activate
119+
def test_revoke_rcs_message():
120+
responses.add(
121+
responses.PATCH,
122+
'https://api-eu.vonage.com/v1/messages/asdf',
123+
)
124+
messages = Messages(
125+
HttpClient(get_mock_jwt_auth(), HttpClientOptions(api_host='api-eu.vonage.com'))
126+
)
127+
messages.http_client.http_client_options.api_host = 'api-eu.vonage.com'
128+
messages.revoke_rcs_message('asdf')
129+
130+
131+
@responses.activate
132+
def test_revoke_rcs_message_not_found():
133+
build_response(
134+
path,
135+
'PATCH',
136+
'https://api-eu.vonage.com/v1/messages/asdf',
137+
'not_found.json',
138+
404,
139+
)
140+
messages = Messages(
141+
HttpClient(get_mock_jwt_auth(), HttpClientOptions(api_host='api-eu.vonage.com'))
142+
)
143+
with raises(HttpRequestError) as e:
144+
messages.revoke_rcs_message('asdf')
145+
146+
assert e.value.response.status_code == 404
147+
assert e.value.response.json()['title'] == 'Not Found'

0 commit comments

Comments
 (0)