Skip to content

Commit ce7d2d2

Browse files
nnsnodnbokdtsk
authored andcommitted
Add new API for Image Carousel (#59)
* Add new api for Image Carousel * Fix D400 in ImageCarouselColumn * Remove debug logger * Fix action array count in ImageCarouselColumn * Fix ImageCarouselColumn#action to single action * Fix Image Carousel's test code * Add ImagePostbackTemplateAction for Image Carousel action * Fix D204 * Replace ImagePostbackTemplateAction to PostbackTemplateAction & delete former class
1 parent 0b4b6b7 commit ce7d2d2

File tree

3 files changed

+209
-9
lines changed

3 files changed

+209
-9
lines changed

linebot/models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,6 @@
7979
PostbackTemplateAction,
8080
MessageTemplateAction,
8181
URITemplateAction,
82+
ImageCarouselTemplate,
83+
ImageCarouselColumn,
8284
)

linebot/models/template.py

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,22 @@
2424
from .send_messages import SendMessage
2525

2626

27+
def _get_action(action):
28+
action_obj = Base.get_or_new_from_json_dict_with_types(
29+
action, {
30+
'postback': PostbackTemplateAction,
31+
'message': MessageTemplateAction,
32+
'uri': URITemplateAction
33+
}
34+
)
35+
return action_obj
36+
37+
2738
def _get_actions(actions):
2839
new_actions = []
2940
if actions:
3041
for action in actions:
31-
action_obj = Base.get_or_new_from_json_dict_with_types(
32-
action, {
33-
'postback': PostbackTemplateAction,
34-
'message': MessageTemplateAction,
35-
'uri': URITemplateAction
36-
}
37-
)
42+
action_obj = _get_action(action)
3843
if action_obj:
3944
new_actions.append(action_obj)
4045

@@ -67,7 +72,8 @@ def __init__(self, alt_text=None, template=None, **kwargs):
6772
template, {
6873
'buttons': ButtonsTemplate,
6974
'confirm': ConfirmTemplate,
70-
'carousel': CarouselTemplate
75+
'carousel': CarouselTemplate,
76+
'image_carousel': ImageCarouselTemplate
7177
}
7278
)
7379

@@ -175,6 +181,35 @@ def __init__(self, columns=None, **kwargs):
175181
self.columns = new_columns
176182

177183

184+
class ImageCarouselTemplate(Template):
185+
"""ImageCarouselTemplate.
186+
187+
https://devdocs.line.me/en/#image-carousel
188+
189+
Template message with multiple images columns which can be cycled like as carousel.
190+
"""
191+
192+
def __init__(self, columns=None, **kwargs):
193+
"""__init__ method.
194+
195+
:param columns: Array of columns.
196+
Max: 5
197+
:type columns: list[T <= :py:class:`linebot.models.template.ImageCarouselColumn`]
198+
:param kwargs:
199+
"""
200+
super(ImageCarouselTemplate, self).__init__(**kwargs)
201+
202+
self.type = 'image_carousel'
203+
204+
new_columns = []
205+
if columns:
206+
for column in columns:
207+
new_columns.append(self.get_or_new_from_json_dict(
208+
column, ImageCarouselColumn
209+
))
210+
self.columns = new_columns
211+
212+
178213
class CarouselColumn(Base):
179214
"""CarouselColumn.
180215
@@ -208,6 +243,32 @@ def __init__(self, text=None, title=None, thumbnail_image_url=None, actions=None
208243
self.actions = _get_actions(actions)
209244

210245

246+
class ImageCarouselColumn(Base):
247+
"""ImageCarouselColumn.
248+
249+
https://devdocs.line.me/en/#column-object-for-image-carousel
250+
"""
251+
252+
def __init__(self, image_url=None, action=None, **kwargs):
253+
"""__init__ method.
254+
255+
:param str image_url: Image URL.
256+
HTTPS
257+
JPEG or PNG
258+
Aspect ratio: 1:1
259+
Max width: 1024px
260+
Max: 1 MB
261+
:param action: Action when image is tapped
262+
Max: 5
263+
:type action: T <= :py:class:`linebot.models.template.TemplateAction`
264+
:param kwargs:
265+
"""
266+
super(ImageCarouselColumn, self).__init__(**kwargs)
267+
268+
self.image_url = image_url
269+
self.action = _get_action(action)
270+
271+
211272
class TemplateAction(with_metaclass(ABCMeta, Base)):
212273
"""Abstract Base Class of TemplateAction."""
213274

tests/api/test_send_template_message.py

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
from linebot.models import (
2626
TemplateSendMessage, ButtonsTemplate,
2727
PostbackTemplateAction, MessageTemplateAction, URITemplateAction,
28-
ConfirmTemplate, CarouselTemplate, CarouselColumn
28+
ConfirmTemplate, CarouselTemplate, CarouselColumn,
29+
ImageCarouselTemplate, ImageCarouselColumn
2930
)
3031

3132

@@ -223,6 +224,73 @@ def setUp(self):
223224
}
224225
}]
225226

227+
self.image_carousel_template_message = TemplateSendMessage(
228+
alt_text='Image carousel template',
229+
template=ImageCarouselTemplate(
230+
columns=[
231+
ImageCarouselColumn(
232+
image_url='https://example.com/'
233+
'item1.jpg',
234+
action=PostbackTemplateAction(
235+
label='postback1',
236+
data='action=buy&itemid=1'
237+
)
238+
),
239+
ImageCarouselColumn(
240+
image_url='https://example.com'
241+
'/item2.jpg',
242+
action=MessageTemplateAction(
243+
label='message2',
244+
text='message text2'
245+
)
246+
),
247+
ImageCarouselColumn(
248+
image_url='https://example.com/'
249+
'item3.jpg',
250+
action=URITemplateAction(
251+
label='uri1',
252+
uri='https://example.com/1'
253+
)
254+
)
255+
]
256+
)
257+
)
258+
259+
self.image_carousel_message = [{
260+
"type": "template",
261+
"altText": "Image carousel template",
262+
"template": {
263+
"type": "image_carousel",
264+
"columns": [
265+
{
266+
"imageUrl": "https://example.com/item1.jpg",
267+
"action": {
268+
"type": "postback",
269+
"label": "postback1",
270+
"data": "action=buy&itemid=1",
271+
"text": None
272+
}
273+
},
274+
{
275+
"imageUrl": "https://example.com/item2.jpg",
276+
"action": {
277+
"type": "message",
278+
"label": "message2",
279+
"text": "message text2"
280+
}
281+
},
282+
{
283+
"imageUrl": "https://example.com/item3.jpg",
284+
"action": {
285+
"type": "uri",
286+
"label": "uri1",
287+
"uri": "https://example.com/1"
288+
}
289+
}
290+
]
291+
}
292+
}]
293+
226294
@responses.activate
227295
def test_push_buttons_template_message(self):
228296
responses.add(
@@ -385,6 +453,75 @@ def test_multicast_carousel_template_message(self):
385453
}
386454
)
387455

456+
@responses.activate
457+
def test_push_image_carousel_template_message(self):
458+
responses.add(
459+
responses.POST,
460+
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/message/push',
461+
json={}, status=200
462+
)
463+
464+
self.tested.push_message('to', self.image_carousel_template_message)
465+
466+
request = responses.calls[0].request
467+
self.assertEqual(request.method, 'POST')
468+
self.assertEqual(
469+
request.url,
470+
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/message/push')
471+
self.assertEqual(
472+
json.loads(request.body),
473+
{
474+
"to": "to",
475+
"messages": self.image_carousel_message
476+
}
477+
)
478+
479+
@responses.activate
480+
def test_reply_image_carousel_template_message(self):
481+
responses.add(
482+
responses.POST,
483+
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/message/reply',
484+
json={}, status=200
485+
)
486+
487+
self.tested.reply_message('replyToken', self.image_carousel_template_message)
488+
489+
request = responses.calls[0].request
490+
self.assertEqual(request.method, 'POST')
491+
self.assertEqual(
492+
request.url,
493+
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/message/reply')
494+
self.assertEqual(
495+
json.loads(request.body),
496+
{
497+
"replyToken": "replyToken",
498+
"messages": self.image_carousel_message
499+
}
500+
)
501+
502+
@responses.activate
503+
def test_multicast_image_carousel_template_message(self):
504+
responses.add(
505+
responses.POST,
506+
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/message/multicast',
507+
json={}, status=200
508+
)
509+
510+
self.tested.multicast(['to1', 'to2'], self.image_carousel_template_message)
511+
512+
request = responses.calls[0].request
513+
self.assertEqual(request.method, 'POST')
514+
self.assertEqual(
515+
request.url,
516+
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/message/multicast')
517+
self.assertEqual(
518+
json.loads(request.body),
519+
{
520+
"to": ['to1', 'to2'],
521+
"messages": self.image_carousel_message
522+
}
523+
)
524+
388525

389526
if __name__ == '__main__':
390527
unittest.main()

0 commit comments

Comments
 (0)