Repository: line/line-bot-sdk-python
Pull request #169 (2019-06-05 07:34:28)

Implement issue link token API
https://github.com/line/line-bot-sdk-python/issues/138


Patch:
diff --git a/README.rst b/README.rst
index 5d31df1..edeb117 100644
--- a/README.rst
+++ b/README.rst
@@ -425,6 +425,18 @@ https://developers.line.biz/en/reference/messaging-api/#cancel-default-rich-menu
 
     line_bot_api.cancel_default_rich_menu()
 
+issue\_link\_token(self, user\_id, timeout=None)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Issues a link token used for the account link feature.
+
+https://developers.line.biz/en/reference/messaging-api/#issue-link-token
+
+.. code:: python
+
+    link_token_response = line_bot_api.issue_link_token(<user_id>)
+    print(link_token_response)
+
 ※ Error handling
 ^^^^^^^^^^^^^^^^
 
@@ -969,7 +981,6 @@ And more... TBD
    :target: https://badge.fury.io/py/line-bot-sdk
 .. |Documentation Status| image:: https://readthedocs.org/projects/line-bot-sdk-python/badge/?version=latest
    :target: http://line-bot-sdk-python.readthedocs.io/en/latest/?badge=latest
-   
 
 License
 --------
diff --git a/examples/flask-kitchensink/app.py b/examples/flask-kitchensink/app.py
index bce1099..650afec 100644
--- a/examples/flask-kitchensink/app.py
+++ b/examples/flask-kitchensink/app.py
@@ -362,6 +362,13 @@ def handle_text_message(event):
                             action=LocationAction(label="label6")
                         ),
                     ])))
+    elif text == 'link_token' and isinstance(event.source, SourceUser):
+        link_token_response = line_bot_api.issue_link_token(event.source.user_id)
+        line_bot_api.reply_message(
+            event.reply_token, [
+                TextSendMessage(text='link_token: ' + link_token_response.link_token)
+            ]
+        )
     else:
         line_bot_api.reply_message(
             event.reply_token, TextSendMessage(text=event.message.text))
diff --git a/linebot/api.py b/linebot/api.py
index b4343a0..fd7bb45 100644
--- a/linebot/api.py
+++ b/linebot/api.py
@@ -23,7 +23,7 @@ from .exceptions import LineBotApiError
 from .http_client import HttpClient, RequestsHttpClient
 from .models import (
     Error, Profile, MemberIds, Content, RichMenuResponse, MessageQuotaResponse,
-    MessageQuotaConsumptionResponse, MessageDeliveryBroadcastResponse
+    MessageQuotaConsumptionResponse, MessageDeliveryBroadcastResponse, IssueLinkTokenResponse
 )
 
 
@@ -738,6 +738,23 @@ class LineBotApi(object):
 
         return MessageQuotaConsumptionResponse.new_from_json_dict(response.json)
 
+    def issue_link_token(self, user_id, timeout=None):
+        """Issues a link token used for the account link feature.
+
+        https://developers.line.biz/en/reference/messaging-api/#issue-link-token
+
+        :param str user_id: User ID for the LINE account to be linked
+        :type timeout: float | tuple(float, float)
+        """
+        response = self._post(
+            '/v2/bot/user/{user_id}/linkToken'.format(
+                user_id=user_id
+            ),
+            timeout=timeout
+        )
+
+        return IssueLinkTokenResponse.new_from_json_dict(response.json)
+
     def _get(self, path, params=None, headers=None, stream=False, timeout=None):
         url = self.endpoint + path
 
diff --git a/linebot/models/__init__.py b/linebot/models/__init__.py
index e4f87c8..07cdcdd 100644
--- a/linebot/models/__init__.py
+++ b/linebot/models/__init__.py
@@ -99,7 +99,8 @@ from .responses import (  # noqa
     MessageQuotaResponse,
     MessageQuotaConsumptionResponse,
     MessageDeliveryBroadcastResponse,
-    Content as MessageContent,  # backward compatibility
+    Content as MessageContent,  # backward compatibility,
+    IssueLinkTokenResponse,
 )
 from .rich_menu import (  # noqa
     RichMenu,
diff --git a/linebot/models/responses.py b/linebot/models/responses.py
index ab09af4..2161133 100644
--- a/linebot/models/responses.py
+++ b/linebot/models/responses.py
@@ -207,3 +207,20 @@ class MessageDeliveryBroadcastResponse(Base):
 
         self.status = status
         self.success = success
+
+
+class IssueLinkTokenResponse(Base):
+    """IssueLinkTokenResponse.
+
+    https://developers.line.biz/en/reference/messaging-api/#issue-link-token
+    """
+
+    def __init__(self, link_token=None, **kwargs):
+        """__init__ method.
+
+        :param str link_token: Link token.
+        :param kwargs:
+        """
+        super(IssueLinkTokenResponse, self).__init__(**kwargs)
+
+        self.link_token = link_token


Test patch:
diff --git a/tests/api/test_issue_link_token.py b/tests/api/test_issue_link_token.py
new file mode 100644
index 0000000..90517e0
--- /dev/null
+++ b/tests/api/test_issue_link_token.py
@@ -0,0 +1,52 @@
+# -*- 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.
+
+from __future__ import unicode_literals, absolute_import
+
+import unittest
+
+import responses
+
+from linebot import (
+    LineBotApi
+)
+
+
+class TestLineBotApi(unittest.TestCase):
+    def setUp(self):
+        self.tested = LineBotApi('channel_secret')
+
+    @responses.activate
+    def test_issue_line_token(self):
+        responses.add(
+            responses.POST,
+            LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/user/user_id/linkToken',
+            json={
+                "linkToken": "xxxx",
+            },
+            status=200
+        )
+
+        issue_link_token_response = self.tested.issue_link_token('user_id')
+
+        request = responses.calls[0].request
+        self.assertEqual(request.method, 'POST')
+        self.assertEqual(
+            request.url,
+            LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/user/user_id/linkToken')
+        self.assertEqual(issue_link_token_response.link_token, 'xxxx')
+
+
+if __name__ == '__main__':
+    unittest.main()