Skip to content

Commit

Permalink
LINE Things scenario execution event (#176)
Browse files Browse the repository at this point in the history
* Add LINE Things scenario execution event

* fix models.things and update test

* fix docs/source/linebot.models.rst
  • Loading branch information
okue committed Jun 18, 2019
1 parent 119b108 commit 8b0007f
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 31 deletions.
24 changes: 24 additions & 0 deletions docs/source/linebot.models.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
linebot.models package
======================

linebot.models.actions module
--------------------------

.. automodule:: linebot.models.actions
:members:
:undoc-members:
:show-inheritance:

linebot.models.base module
--------------------------

Expand Down Expand Up @@ -49,6 +57,14 @@ linebot.models.responses module
:undoc-members:
:show-inheritance:

linebot.models.rich_menu module
-------------------------------

.. automodule:: linebot.models.rich_menu
:members:
:undoc-members:
:show-inheritance:

linebot.models.send_messages module
-----------------------------------

Expand All @@ -72,3 +88,11 @@ linebot.models.template module
:members:
:undoc-members:
:show-inheritance:

linebot.models.things module
------------------------------

.. automodule:: linebot.models.things
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions linebot/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,10 @@
ImageCarouselTemplate,
ImageCarouselColumn,
)
from .things import ( # noqa
DeviceLink,
DeviceUnlink,
ScenarioResult,
ActionResult,
Things,
)
46 changes: 19 additions & 27 deletions linebot/models/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@

from future.utils import with_metaclass

from .base import Base
from .messages import (
from linebot.models.base import Base
from linebot.models.messages import (
TextMessage,
ImageMessage,
VideoMessage,
Expand All @@ -30,7 +30,13 @@
StickerMessage,
FileMessage
)
from .sources import SourceUser, SourceGroup, SourceRoom
from linebot.models.sources import SourceUser, SourceGroup, SourceRoom
from linebot.models.things import (
DeviceUnlink,
DeviceLink,
ScenarioResult,
)
from linebot.models.things import Things # noqa


class Event(with_metaclass(ABCMeta, Base)):
Expand Down Expand Up @@ -360,20 +366,20 @@ class ThingsEvent(Event):
"""Webhook ThingsEvent.
https://developers.line.biz/en/reference/messaging-api/#device-link-event
https://developers.line.biz/en/reference/messaging-api/#device-unlink-event
https://developers.line.biz/en/reference/messaging-api/#scenario-result-event
Indicates that a LINE Things-compatible device has been linked with LINE by
a user operation.
Event sent from LINE Things Webhook service.
"""

def __init__(self, timestamp=None, source=None, reply_token=None, things=None, **kwargs):
"""__init__ method.
:param long timestamp: Time of the event in milliseconds
:param source: Source object
:type source: T <= :py:class:`linebot.models.sources.Source`
:param str reply_token: Reply token
:param things: Things object
:type things: :py:class:`linebot.models.events.Things`
:type things: T <= :py:class:`linebot.models.things.Things`
:param kwargs:
"""
super(ThingsEvent, self).__init__(
Expand All @@ -382,8 +388,12 @@ def __init__(self, timestamp=None, source=None, reply_token=None, things=None, *

self.type = 'things'
self.reply_token = reply_token
self.things = self.get_or_new_from_json_dict(
things, Things
self.things = self.get_or_new_from_json_dict_with_types(
things, {
'link': DeviceLink,
'unlink': DeviceUnlink,
'scenarioResult': ScenarioResult,
}
)


Expand Down Expand Up @@ -498,21 +508,3 @@ def __init__(self, result=None, nonce=None, **kwargs):

self.result = result
self.nonce = nonce


class Things(Base):
"""Things.
https://developers.line.biz/en/docs/line-things/develop-bot/#link-event
"""

def __init__(self, device_id=None, type=None, **kwargs):
"""__init__ method.
:param str device_id: Device ID of the device that was linked with LINE.
:param str type: link or unlink
"""
super(Things, self).__init__(**kwargs)

self.device_id = device_id
self.type = type
150 changes: 150 additions & 0 deletions linebot/models/things.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# -*- coding: utf-8 -*-

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

"""linebot.models.things module."""

from __future__ import unicode_literals

from abc import ABCMeta

from future.utils import with_metaclass

from .base import Base


class Things(with_metaclass(ABCMeta, Base)):
"""Abstract Base Class of Things."""

def __init__(self, device_id=None, **kwargs):
"""__init__ method.
:param str device_id: Device ID.
:param kwargs:
"""
super(Things, self).__init__(**kwargs)
self.device_id = device_id


class DeviceLink(Things):
"""DeviceLink.
https://developers.line.biz/en/reference/messaging-api/#device-link-event
Indicates that a user linked a device with LINE.
"""

def __init__(self, device_id=None, **kwargs):
"""__init__ method.
:param str device_id: Device ID of the device that has been linked with LINE.
:param kwargs:
"""
super(DeviceLink, self).__init__(device_id=device_id, **kwargs)

self.type = 'link'


class DeviceUnlink(Things):
"""DeviceUnlink.
https://developers.line.biz/en/reference/messaging-api/#device-unlink-event
Indicates that the user unlinked a device from LINE.
"""

def __init__(self, device_id=None, **kwargs):
"""__init__ method.
:param str device_id: Device ID of the device that was unlinked from LINE.
:param kwargs:
"""
super(DeviceUnlink, self).__init__(device_id=device_id, **kwargs)

self.type = 'unlink'


class ScenarioResult(Things):
"""ScenarioResult.
https://developers.line.biz/en/reference/messaging-api/#scenario-result-event
Indicates that an automatic communication scenario has been executed.
"""

def __init__(self, device_id=None, result=None, **kwargs):
"""__init__ method.
:param str device_id: Device ID of the device that executed the scenario.
:param str result: ScenarioResultPayload object.
:param kwargs:
"""
super(ScenarioResult, self).__init__(device_id=device_id, **kwargs)

self.type = 'scenarioResult'
self.result = self.get_or_new_from_json_dict(
result, ScenarioResultPayload
)


class ScenarioResultPayload(Base):
"""ScenarioResultPayload."""

def __init__(self, scenario_id=None, revision=None, start_time=None,
result_code=None, end_time=None, action_results=None,
ble_notification_payload=None, error_reason=None, **kwargs):
"""__init__ method.
:param str scenario_id: Scenario ID executed.
:param long revision: Revision number.
:param long start_time: Timestamp for when execution of scenario
action started (milliseconds).
:param long end_time: Timestamp for when execution of scenario
was completed (milliseconds).
:param str result_code: Scenario execution completion status.
:param action_results: Array of actions specified in a scenario.
:type action_results: list[T <= :py:class:`linebot.models.things.ActionResult`]
:param str ble_notification_payload: Data contained in notification.
:param str error_reason: Error response.
:param kwargs:
"""
super(ScenarioResultPayload, self).__init__(**kwargs)

self.scenario_id = scenario_id
self.revision = revision
self.start_time = start_time
self.end_time = end_time
self.result_code = result_code
self.action_results = [self.get_or_new_from_json_dict(it, ActionResult)
for it in action_results]
self.ble_notification_payload = ble_notification_payload
self.error_reason = error_reason


class ActionResult(Base):
"""ActionResult.
Execution result of individual operations specified in action
"""

def __init__(self, type=None, data=None, **kwargs):
"""__init__ method.
:param str type: Type of the executed action.
:param str data: Base64-encoded binary data.
:param kwargs:
"""
super(ActionResult, self).__init__(**kwargs)

self.type = type
self.data = data
33 changes: 29 additions & 4 deletions tests/test_webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
MemberJoinedEvent, MemberLeftEvent, ThingsEvent,
TextMessage, ImageMessage, VideoMessage, AudioMessage,
LocationMessage, StickerMessage, FileMessage,
SourceUser, SourceRoom, SourceGroup
)
SourceUser, SourceRoom, SourceGroup,
DeviceLink, DeviceUnlink, ScenarioResult, ActionResult)


class TestSignatureValidator(unittest.TestCase):
Expand Down Expand Up @@ -308,8 +308,9 @@ def test_parse(self):
self.assertIsInstance(events[19].source, SourceUser)
self.assertEqual(events[19].source.type, 'user')
self.assertEqual(events[19].source.user_id, 'U206d25c2ea6bd87c17655609a1c37cb8')
self.assertEqual(events[19].things.device_id, 't2c449c9d1')
self.assertIsInstance(events[19].things, DeviceLink)
self.assertEqual(events[19].things.type, 'link')
self.assertEqual(events[19].things.device_id, 't2c449c9d1')

# MemberJoinedEvent
self.assertIsInstance(events[20], MemberJoinedEvent)
Expand Down Expand Up @@ -344,8 +345,9 @@ def test_parse(self):
self.assertIsInstance(events[22].source, SourceUser)
self.assertEqual(events[22].source.type, 'user')
self.assertEqual(events[22].source.user_id, 'U206d25c2ea6bd87c17655609a1c37cb8')
self.assertEqual(events[22].things.device_id, 't2c449c9d1')
self.assertIsInstance(events[22].things, DeviceUnlink)
self.assertEqual(events[22].things.type, 'unlink')
self.assertEqual(events[22].things.device_id, 't2c449c9d1')

# MessageEvent, SourceUser, FileMessage
self.assertIsInstance(events[23], MessageEvent)
Expand All @@ -362,6 +364,29 @@ def test_parse(self):
self.assertEqual(events[23].message.file_name, "file.txt")
self.assertEqual(events[23].message.file_size, 2138)

# ThingsEvent, SourceUser, scenarioResult
self.assertIsInstance(events[24], ThingsEvent)
self.assertEqual(events[24].reply_token, 'nHuyWiB7yP5Zw52FIkcQobQuGDXCTA')
self.assertEqual(events[24].type, 'things')
self.assertEqual(events[24].timestamp, 1547817848122)
self.assertIsInstance(events[24].source, SourceUser)
self.assertEqual(events[24].source.type, 'user')
self.assertEqual(events[24].source.user_id, 'U206d25c2ea6bd87c17655609a1c37cb8')
self.assertIsInstance(events[24].things, ScenarioResult)
self.assertEqual(events[24].things.type, 'scenarioResult')
self.assertEqual(events[24].things.device_id, 't2c449c9d1')
self.assertEqual(events[24].things.result.scenario_id, 'XXX')
self.assertEqual(events[24].things.result.revision, 2)
self.assertEqual(events[24].things.result.start_time, 1547817845950)
self.assertEqual(events[24].things.result.end_time, 1547817845952)
self.assertEqual(events[24].things.result.result_code, 'success')
self.assertEqual(events[24].things.result.ble_notification_payload, 'AQ==')
self.assertIsInstance(events[24].things.result.action_results[0], ActionResult)
self.assertEqual(events[24].things.result.action_results[0].type, 'binary')
self.assertEqual(events[24].things.result.action_results[0].data, '/w==')
self.assertIsInstance(events[24].things.result.action_results[1], ActionResult)
self.assertEqual(events[24].things.result.action_results[1].type, 'void')


class TestWebhookHandler(unittest.TestCase):
def setUp(self):
Expand Down
30 changes: 30 additions & 0 deletions tests/text/webhook.json
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,36 @@
"fileName": "file.txt",
"fileSize": 2138
}
},
{
"replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
"type": "things",
"source": {
"type": "user",
"userId": "U206d25c2ea6bd87c17655609a1c37cb8"
},
"timestamp": 1547817848122,
"things": {
"type": "scenarioResult",
"deviceId": "t2c449c9d1",
"result": {
"scenarioId": "XXX",
"revision": 2,
"startTime": 1547817845950,
"endTime": 1547817845952,
"resultCode": "success",
"bleNotificationPayload": "AQ==",
"actionResults": [
{
"type": "binary",
"data": "/w=="
},
{
"type": "void"
}
]
}
}
}
]
}

0 comments on commit 8b0007f

Please sign in to comment.