Skip to content

Commit 5fb3d27

Browse files
authored
Support emoji length and X-Line-Retry-key (#270)
#266 Emojis - add length paramter X-Line-Retry-key - modified exception string condition if accepted_request_id was shown - add retry_key parameter
1 parent 911fb8f commit 5fb3d27

File tree

7 files changed

+257
-8
lines changed

7 files changed

+257
-8
lines changed

linebot/api.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ def reply_message(self, reply_token, messages, notification_disabled=False, time
109109
'/v2/bot/message/reply', data=json.dumps(data), timeout=timeout
110110
)
111111

112-
def push_message(self, to, messages, notification_disabled=False, timeout=None):
112+
def push_message(
113+
self, to, messages,
114+
retry_key=None, notification_disabled=False, timeout=None):
113115
"""Call push message API.
114116
115117
https://developers.line.biz/en/reference/messaging-api/#send-push-message
@@ -121,6 +123,7 @@ def push_message(self, to, messages, notification_disabled=False, timeout=None):
121123
Max: 5
122124
:type messages: T <= :py:class:`linebot.models.send_messages.SendMessage` |
123125
list[T <= :py:class:`linebot.models.send_messages.SendMessage`]
126+
:param retry_key: (optional) Arbitrarily generated UUID in hexadecimal notation.
124127
:param bool notification_disabled: (optional) True to disable push notification
125128
when the message is sent. The default value is False.
126129
:param timeout: (optional) How long to wait for the server
@@ -132,6 +135,9 @@ def push_message(self, to, messages, notification_disabled=False, timeout=None):
132135
if not isinstance(messages, (list, tuple)):
133136
messages = [messages]
134137

138+
if retry_key:
139+
self.headers['X-Line-Retry-Key'] = retry_key
140+
135141
data = {
136142
'to': to,
137143
'messages': [message.as_json_dict() for message in messages],
@@ -142,7 +148,7 @@ def push_message(self, to, messages, notification_disabled=False, timeout=None):
142148
'/v2/bot/message/push', data=json.dumps(data), timeout=timeout
143149
)
144150

145-
def multicast(self, to, messages, notification_disabled=False, timeout=None):
151+
def multicast(self, to, messages, retry_key=None, notification_disabled=False, timeout=None):
146152
"""Call multicast API.
147153
148154
https://developers.line.biz/en/reference/messaging-api/#send-multicast-message
@@ -157,6 +163,7 @@ def multicast(self, to, messages, notification_disabled=False, timeout=None):
157163
Max: 5
158164
:type messages: T <= :py:class:`linebot.models.send_messages.SendMessage` |
159165
list[T <= :py:class:`linebot.models.send_messages.SendMessage`]
166+
:param retry_key: (optional) Arbitrarily generated UUID in hexadecimal notation.
160167
:param bool notification_disabled: (optional) True to disable push notification
161168
when the message is sent. The default value is False.
162169
:param timeout: (optional) How long to wait for the server
@@ -168,6 +175,9 @@ def multicast(self, to, messages, notification_disabled=False, timeout=None):
168175
if not isinstance(messages, (list, tuple)):
169176
messages = [messages]
170177

178+
if retry_key:
179+
self.headers['X-Line-Retry-Key'] = retry_key
180+
171181
data = {
172182
'to': to,
173183
'messages': [message.as_json_dict() for message in messages],
@@ -178,7 +188,7 @@ def multicast(self, to, messages, notification_disabled=False, timeout=None):
178188
'/v2/bot/message/multicast', data=json.dumps(data), timeout=timeout
179189
)
180190

181-
def broadcast(self, messages, notification_disabled=False, timeout=None):
191+
def broadcast(self, messages, retry_key=None, notification_disabled=False, timeout=None):
182192
"""Call broadcast API.
183193
184194
https://developers.line.biz/en/reference/messaging-api/#send-broadcast-message
@@ -189,6 +199,7 @@ def broadcast(self, messages, notification_disabled=False, timeout=None):
189199
Max: 5
190200
:type messages: T <= :py:class:`linebot.models.send_messages.SendMessage` |
191201
list[T <= :py:class:`linebot.models.send_messages.SendMessage`]
202+
:param retry_key: (optional) Arbitrarily generated UUID in hexadecimal notation.
192203
:param bool notification_disabled: (optional) True to disable push notification
193204
when the message is sent. The default value is False.
194205
:param timeout: (optional) How long to wait for the server
@@ -201,6 +212,9 @@ def broadcast(self, messages, notification_disabled=False, timeout=None):
201212
if not isinstance(messages, (list, tuple)):
202213
messages = [messages]
203214

215+
if retry_key:
216+
self.headers['X-Line-Retry-Key'] = retry_key
217+
204218
data = {
205219
'messages': [message.as_json_dict() for message in messages],
206220
'notificationDisabled': notification_disabled,
@@ -212,7 +226,9 @@ def broadcast(self, messages, notification_disabled=False, timeout=None):
212226

213227
return BroadcastResponse(request_id=response.headers.get('X-Line-Request-Id'))
214228

215-
def narrowcast(self, messages, recipient=None, filter=None, limit=None, timeout=None):
229+
def narrowcast(
230+
self, messages,
231+
retry_key=None, recipient=None, filter=None, limit=None, timeout=None):
216232
"""Call narrowcast API.
217233
218234
https://developers.line.biz/en/reference/messaging-api/#send-narrowcast-message
@@ -224,6 +240,7 @@ def narrowcast(self, messages, recipient=None, filter=None, limit=None, timeout=
224240
Max: 5
225241
:type messages: T <= :py:class:`linebot.models.send_messages.SendMessage` |
226242
list[T <= :py:class:`linebot.models.send_messages.SendMessage`]
243+
:param retry_key: (optional) Arbitrarily generated UUID in hexadecimal notation.
227244
:param recipient: audience object of recipient
228245
:type recipient: T <= :py:class:`linebot.models.recipient.AudienceRecipient`
229246
:param filter: demographic filter of recipient
@@ -240,6 +257,9 @@ def narrowcast(self, messages, recipient=None, filter=None, limit=None, timeout=
240257
if not isinstance(messages, (list, tuple)):
241258
messages = [messages]
242259

260+
if retry_key:
261+
self.headers['X-Line-Retry-Key'] = retry_key
262+
243263
data = {
244264
'messages': [message.as_json_dict() for message in messages],
245265
'recipient': recipient.as_json_dict(),
@@ -1156,5 +1176,6 @@ def __check_error(response):
11561176
status_code=response.status_code,
11571177
headers=dict(response.headers.items()),
11581178
request_id=response.headers.get('X-Line-Request-Id'),
1179+
accepted_request_id=response.headers.get('X-Line-Accepted-Request-Id'),
11591180
error=Error.new_from_json_dict(response.json)
11601181
)

linebot/exceptions.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,21 @@ def __init__(self, message='-'):
5858
class LineBotApiError(BaseError):
5959
"""When LINE Messaging API response error, this error will be raised."""
6060

61-
def __init__(self, status_code, headers, request_id=None, error=None):
61+
def __init__(
62+
self,
63+
status_code,
64+
headers,
65+
request_id=None,
66+
accepted_request_id=None,
67+
error=None
68+
):
6269
"""__init__ method.
6370
6471
:param int status_code: HTTP status code
6572
:param headers: Response headers
6673
:type headers: dict[str, str]
6774
:param str request_id: (optional) Request ID. A unique ID is generated for each request
75+
:param str accepted_request_id: (optional) The same request has already been accepted
6876
:param error: (optional) Error class object.
6977
:type error: :py:class:`linebot.models.error.Error`
7078
"""
@@ -73,12 +81,23 @@ def __init__(self, status_code, headers, request_id=None, error=None):
7381
self.status_code = status_code
7482
self.headers = headers
7583
self.request_id = request_id
84+
self.accepted_request_id = accepted_request_id
7685
self.error = error
7786

7887
def __str__(self):
7988
"""str.
8089
8190
:rtype: str
8291
"""
92+
if self.accepted_request_id:
93+
return "{0}: status_code={1}, request_id={2}, " \
94+
"accepted_request_id={3}, error_response={4}, headers={5}" \
95+
.format(self.__class__.__name__,
96+
self.status_code,
97+
self.request_id,
98+
self.accepted_request_id,
99+
self.error,
100+
self.headers)
83101
return '{0}: status_code={1}, request_id={2}, error_response={3}, headers={4}'.format(
84-
self.__class__.__name__, self.status_code, self.request_id, self.error, self.headers)
102+
self.__class__.__name__, self.status_code, self.request_id, self.error,
103+
self.headers)

linebot/models/emojis.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@ class Emojis(with_metaclass(ABCMeta, Base)):
3030
3131
"""
3232

33-
def __init__(self, index=None, product_id=None, emoji_id=None, **kwargs):
33+
def __init__(self, index=None, length=None, product_id=None, emoji_id=None, **kwargs):
3434
"""__init__ method.
3535
3636
:param kwargs:
3737
"""
3838
super(Emojis, self).__init__(**kwargs)
3939

4040
self.index = index
41+
self.length = length
4142
self.product_id = product_id
4243
self.emoji_id = emoji_id

tests/api/test_narrowcast_message.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,90 @@ def test_narrowcast_text_message(self):
217217
)
218218
self.assertEqual('request_id_test', response.request_id)
219219

220+
@responses.activate
221+
def test_narrowcast_text_message_with_retry_key(self):
222+
responses.add(
223+
responses.POST,
224+
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/message/narrowcast',
225+
json={}, status=200,
226+
headers={
227+
'X-Line-Request-Id': 'request_id_test',
228+
'X-Line-Retry-Key': '123e4567-e89b-12d3-a456-426614174000'
229+
},
230+
)
231+
232+
response = self.tested.narrowcast(
233+
self.text_message,
234+
recipient=And(
235+
AudienceRecipient(group_id=5614991017776),
236+
Not(AudienceRecipient(group_id=4389303728991))
237+
),
238+
filter=Filter(
239+
demographic=Or(
240+
And(
241+
GenderFilter(one_of=["male", "female"])
242+
)
243+
)
244+
),
245+
limit=Limit(max=100),
246+
retry_key='123e4567-e89b-12d3-a456-426614174000',
247+
)
248+
249+
request = responses.calls[0].request
250+
self.assertEqual(
251+
request.url,
252+
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/message/narrowcast')
253+
self.assertEqual(request.method, 'POST')
254+
self.assertEqual(
255+
request.headers['X-Line-Retry-Key'],
256+
'123e4567-e89b-12d3-a456-426614174000'
257+
)
258+
self.assertEqual(
259+
json.loads(request.body),
260+
{
261+
"messages": self.message,
262+
"recipient": {
263+
"type": "operator",
264+
"and": [
265+
{
266+
'audienceGroupId': 5614991017776,
267+
'type': 'audience'
268+
},
269+
{
270+
"type": "operator",
271+
"not": {
272+
"type": "audience",
273+
"audienceGroupId": 4389303728991
274+
}
275+
}
276+
]
277+
},
278+
"filter": {
279+
"demographic": {
280+
"type": "operator",
281+
"or": [
282+
{
283+
"type": "operator",
284+
"and": [
285+
{
286+
"type": "gender",
287+
"oneOf": [
288+
"male",
289+
"female"
290+
]
291+
}
292+
]
293+
}
294+
]
295+
}
296+
},
297+
"limit": {
298+
"max": 100
299+
}
300+
}
301+
)
302+
self.assertEqual('request_id_test', response.request_id)
303+
220304
@responses.activate
221305
def test_get_progress_status_narrowcast(self):
222306
responses.add(

0 commit comments

Comments
 (0)