class Api(): def __init__(self, token, secret): self._app = Flask(__name__) self._api = LineBotApi(token) self._handler = WebhookHandler(secret) self.route() @_handler.add(MessageEvent, message=TextMessage) def callback(self): signature = request.headers['X-Line-Signature'] body = request.get_data(as_text=True) self._app.logger.info("Request body: " + body) print(body, signature) self._handler.handle(body, signature) return 'OK' # @handler.add(MessageEvent, message=TextMessage) def pretty_echo(self, event): self._api.reply_message(event.reply_token, TextSendMessage(text='text')) def route(self): self._handler.add(MessageEvent, message=TextMessage) self._app.add_url_rule('/callback', methods=['POST'], view_func=self.callback) def run(self, port=8080): self._app.run(port=port)
class BotEcho: def __init__(self,event,access_token,channel_secret): self.event = event self.bot = LineBotApi(access_token) self.handler = WebhookHandler(channel_secret) self.body = json.loads(event['body'])['events'][0] self.sender_id = self.body['source']['userId'] self.text_message = self.body['message']['text'] self.log(sender=self.sender_id,to='self',message=self.text_message) @property def signature_check(self): signature = self.event['headers']['X-Line-Signature'] try: self.handler.handle(self.event['body'], signature) return 200 except InvalidSignatureError: return 400 def send_reply(self,message): self.log(sender='self',to=self.sender_id,message=message) response = self.bot.reply_message(self.body['replyToken'], \ TextSendMessage(text=message)) return response def log(self,sender,to,message): log_head = ['to','message'] log_value = [to, message] response = DynamoDB(table_name, key_name, sec_key_name)\ .put(sender,log_head,log_value) print(response) return response
def lambda_handler(event, context): # LINE_USER_INFO YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"] YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"] line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN) handler = WebhookHandler(YOUR_CHANNEL_SECRET) # get X-Line-Signature header value signature = event["headers"]['x-line-signature'] # get request body as text requestBody = event["body"] print("***GET REQUEST***\n", event) # add handler method @handler.add(MessageEvent) def text_message(line_event): try: if (line_event.message.type == 'image'): print("***画像を受信***") message_id = line_event.message.id message_content = line_bot_api.get_message_content(message_id) # # tempfileに受け付けた画像を書き込み with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as fp: tempfile_name = fp.name for chunk in message_content.iter_content(): fp.write(chunk) googleDrive_path = "https://drive.google.com/drive/folders/1P4of3548yOXKgygy2a-FwIkIN8Qx3yvr" message = f'ナイスファイト!ダァーー!\n{googleDrive_path}' line_bot_api.reply_message(line_event.reply_token, TextSendMessage(text=message)) # tempfileの画像をgoogleDriveに転送 sendMessage = uploadFileToGoogleDrive(tempfile_name) else: # 受付メッセージをおうむ返し text = f'「{line_event.message.text}」\n画像を送信しろ!!' line_bot_api.reply_message(line_event.reply_token, TextSendMessage(text=text)) except Exception as e: line_bot_api.reply_message(line_event.reply_token, TextSendMessage(text=e)) try: handler.handle(requestBody, signature) except LineBotApiError as e: logger.error("Got exception from LINE Messaging API: %s\n" % e.message) for m in e.error.details: logger.error(" %s: %s" % (m.property, m.message)) except InvalidSignatureError: logger.error("sending message happen error") except Exception as e: logger.error("handler error\n", e)
def post(slef, request, channel_id): line_account = get_object_or_404(LineAccounts, active=True, channel_id=channel_id) line_bot_api = LineBotApi(line_account.channel_access_token) handler = WebhookHandler(line_account.channel_secret) signature = request.META.get('HTTP_X_LINE_SIGNATURE', '') body = request.body.decode('utf-8') @handler.add(MessageEvent) def handle_message(event): contact = line_account.getProfile(event.source) chat_session_list = ChatSession.objects.filter(line_account=line_account, line_contact=contact, end_conversation_at=None) if not chat_session_list : token = hashlib.md5("{}.{}".format(contact.contact_id, str(datetime.now())).encode('utf-8')).hexdigest() chat_session = ChatSession( token = token, line_account = line_account, line_contact = contact, ) chat_session.save() else: chat_session = chat_session_list.first() text = '' file = None image = None if event.message.type == 'text': text = event.message.text # status coversation # 0 คือ Contact คุยกับ Line@ # 1 คือ Line@ คุยกับ Contact # ChatSession.objects.filter(line_account=line_account, line_contact=line_contact) chat_message = ChatMessage( session = chat_session, line_account = line_account, line_contact = contact, message_type = event.message.type, text = text, image = image, file = file, raw_data = body, status_coversation = 0 ) chat_message.save() try: handler.handle(body, signature) # if not line_channel.is_verify_webhook: # Verify webhook # line_channel.is_verify_webhook = True # line_channel.save() except InvalidSignatureError: return HttpResponseBadRequest('400 - Bad request') return HttpResponse('OK')
class ChatbotHandler(): def __init__(self, load_clients, redis=None): self.handler = WebhookHandler(os.environ.get('CHANNEL_SECRET')) self.bot = LineBotApi(os.environ.get('CHANNEL_ACCESS_TOKEN')) load_clients(ClientHandler(self.handler, self.bot, redis)).start() def handle(self, request, logger=None): body = request.get_data(as_text=True) if (logger): logger.info('Request body: {}'.format(body)) self.handler.handle(body, request.headers.get('X-Line-Signature'))
def verify_auth(request): channel_secret = config.get('CHANNEL_SECRET') handler = WebhookHandler(channel_secret) body = request.get_data(as_text=True) signature = request.headers['X-Line-Signature'] try: handler.handle(body, signature) except InvalidSignatureError: print('Invalid signature.') return 'Invalid signature.', 400 return 'OK'
def webhook(): line_bot_api = LineBotApi(os.environ.get('LINE_CHANNEL_TOKEN')) handler = WebhookHandler(os.environ.get('LINE_CHANNEL_SECRET_KEY')) # get X-Line-Signature header value signature = request.headers['X-Line-Signature'] body = request.get_data(as_text=True) event = json.loads(body) print(event) try: handler.handle(body, signature) except InvalidSignatureError: print( "Invalid signature. Please check your channel access token/channel secret.") abort(400) token = event['events'][0]['replyToken'] if token == "00000000000000000000000000000000": pass else: line_bot_api.reply_message(token, TextSendMessage( text=event['events'][0]['message']['text'])) return 'OK'
## 1 ## #Webhookからのリクエストをチェックします。 @app.route("/callback", methods=['POST']) def callback(): # リクエストヘッダーから署名検証のための値を取得します。 signature = request.headers['X-Line-Signature'] # リクエストボディを取得します。 body = request.get_data(as_text=True) app.logger.info("Request body: " + body) # handle webhook body # 署名を検証し、問題なければhandleに定義されている関数を呼び出す。 try: handler.handle(body, signature) # 署名検証で失敗した場合、例外を出す。 except InvalidSignatureError: abort(400) # handleの処理を終えればOK return 'OK' ## 2 ## ############################################### #LINEのメッセージの取得と返信内容の設定(オウム返し) ############################################### #LINEでMessageEvent(普通のメッセージを送信された場合)が起こった場合に、 #def以下の関数を実行します。 #reply_messageの第一引数のevent.reply_tokenは、イベントの応答に用いるトークンです。 #第二引数には、linebot.modelsに定義されている返信用のTextSendMessageオブジェクトを渡しています。
class TestWebhookHandler(unittest.TestCase): def setUp(self): self.handler = WebhookHandler('channel_secret') self.calls = [] @self.handler.add(MessageEvent, message=TextMessage) def message_text(event): self.calls.append('1 ' + event.type + '_' + event.message.type) @self.handler.add(MessageEvent, message=(ImageMessage, VideoMessage, AudioMessage)) def message_content(event): self.calls.append('2 ' + event.type + '_' + event.message.type) @self.handler.add(MessageEvent, message=StickerMessage) def message_sticker(event): self.calls.append('3 ' + event.type + '_' + event.message.type) @self.handler.add(MessageEvent) def message(event): self.calls.append(event.type + '_' + event.message.type) @self.handler.add(FollowEvent) def follow(event): self.calls.append('4 ' + event.type) @self.handler.add(JoinEvent) def join(event): self.calls.append('5 ' + event.type) @self.handler.add(PostbackEvent) def postback(event): self.calls.append('6 ' + event.type) @self.handler.add(BeaconEvent) def beacon(event): self.calls.append('7 ' + event.type) @self.handler.default() def default(event): self.calls.append('default ' + event.type) def test_handler(self): file_dir = os.path.dirname(__file__) webhook_sample_json_path = os.path.join(file_dir, 'text', 'webhook.json') with open(webhook_sample_json_path) as fp: body = fp.read() # mock self.handler.parser.signature_validator.validate = lambda a, b: True self.handler.handle(body, 'signature') self.assertEqual(self.calls[0], '1 message_text') self.assertEqual(self.calls[1], '2 message_image') self.assertEqual(self.calls[2], '2 message_video') self.assertEqual(self.calls[3], '2 message_audio') self.assertEqual(self.calls[4], 'message_location') self.assertEqual(self.calls[5], '3 message_sticker') self.assertEqual(self.calls[6], '4 follow') self.assertEqual(self.calls[7], 'default unfollow') self.assertEqual(self.calls[8], '5 join') self.assertEqual(self.calls[9], 'default leave') self.assertEqual(self.calls[10], '6 postback') self.assertEqual(self.calls[11], '7 beacon') self.assertEqual(self.calls[12], '7 beacon') self.assertEqual(self.calls[13], '1 message_text') self.assertEqual(self.calls[14], '1 message_text') self.assertEqual(self.calls[15], '6 postback') self.assertEqual(self.calls[16], '6 postback') self.assertEqual(self.calls[17], '6 postback')
class TestWebhookHandler(unittest.TestCase): def setUp(self): self.handler = WebhookHandler('channel_secret') @self.handler.add(MessageEvent, message=TextMessage) def message_text(event, destination): self.assertEqual('message', event.type) self.assertEqual('text', event.message.type) self.assertEqual('U123', destination) @self.handler.add(MessageEvent, message=(ImageMessage, VideoMessage, AudioMessage)) def message_content(event): self.assertEqual('message', event.type) self.assertIn(event.message.type, ['image', 'video', 'audio']) @self.handler.add(MessageEvent, message=StickerMessage) def message_sticker(event): self.assertEqual('message', event.type) self.assertEqual('sticker', event.message.type) @self.handler.add(MessageEvent) def message(event): self.assertEqual('message', event.type) self.assertNotIn(event.message.type, ['text', 'image', 'video', 'audio', 'sticker']) @self.handler.add(FollowEvent) def follow(event, destination): self.assertEqual('follow', event.type) self.assertEqual('U123', destination) @self.handler.add(JoinEvent) def join(event): self.assertEqual('join', event.type) @self.handler.add(PostbackEvent) def postback(event): self.assertEqual('postback', event.type) @self.handler.add(BeaconEvent) def beacon(event): self.assertEqual('beacon', event.type) @self.handler.add(AccountLinkEvent) def account_link(event): self.assertEqual('accountLink', event.type) @self.handler.default() def default(event): self.assertNotIn(event.type, [ 'message', 'follow', 'join', 'postback', 'beacon', 'accountLink' ]) def test_handler(self): file_dir = os.path.dirname(__file__) webhook_sample_json_path = os.path.join(file_dir, 'text', 'webhook.json') with open(webhook_sample_json_path) as fp: body = fp.read() # mock self.handler.parser.signature_validator.validate = lambda a, b: True self.handler.handle(body, 'signature')
class LineEventHandler(): @classmethod def initialize(self): self.line_client = LineBotApi( str(os.environ.get('CHANNEL_ACCESS_TOKEN'))) self.line_handler = WebhookHandler( str(os.environ.get('CHANNEL_SECRET'))) # テキストメッセージハンドラ @self.line_handler.add(MessageEvent, message=TextMessage) def handle_message(event): url = os.environ.get('API_APP_MESSAGE') body = { 'request_message': event.message.text, 'user_id': event.source.user_id, 'client': 'line', 'config': {}, 'action': '' } @gen.coroutine def requestasync(): http_client = httpclient.AsyncHTTPClient() http_req = httpclient.HTTPRequest(url, method='POST') http_req.headers = { 'Access-Token': os.environ['API_APP_ACCESS_TOKEN'] } http_req.body = json.dumps(body).encode() raw_response = yield http_client.fetch(http_req) self.handle_response(event, raw_response) requestasync() # ポストバックアクションハンドラ @self.line_handler.add(PostbackEvent) def handle_message(event): print('hook') url = os.environ.get('API_APP_MESSAGE') body = { 'request_message': '', 'user_id': event.source.user_id, 'client': 'line', 'config': {}, 'action': event.postback.data } @gen.coroutine def requestasync(): http_client = httpclient.AsyncHTTPClient() http_req = httpclient.HTTPRequest(url, method='POST') http_req.headers = { 'Access-Token': os.environ['API_APP_ACCESS_TOKEN'] } http_req.body = json.dumps(body).encode() raw_response = yield http_client.fetch(http_req) self.handle_response(event, raw_response) requestasync() # 位置情報メッセージハンドラ @self.line_handler.add(MessageEvent, message=LocationMessage) def handle_message(event): url = os.environ.get('API_APP_ADDRESS') body = { 'user_id': event.source.user_id, 'longitude': event.message.longitude, 'latitude': event.message.latitude } @gen.coroutine def requestasync(): http_client = httpclient.AsyncHTTPClient() http_req = httpclient.HTTPRequest(url, method='POST') http_req.headers = { 'Access-Token': os.environ['API_APP_ACCESS_TOKEN'] } http_req.body = json.dumps(body).encode() raw_response = yield http_client.fetch(http_req) self.handle_response(event, raw_response) requestasync() @classmethod def handle_request(self, body, signature): self.line_handler.handle(body, signature) @classmethod def handle_response(self, event, raw_response): raw_body = raw_response.body.decode('utf-8') response = json.loads(raw_body) reply = [] for index, message in enumerate(response['messages']): mes = ResponseFactory.create_response(message) reply.append(mes) self.line_client.reply_message(event.reply_token, reply)
class LineSDK(): def __init__(self, access_token: str, channel_secret: str, prefix: str = "!"): self.lineapi = LineBotApi(access_token) self.handler = WebhookHandler(channel_secret) self.prefix = prefix self.commands = {} self._pre_start() def handle(self, request) -> str: signature = request.headers['X-Line-Signature'] body = request.get_data(as_text=True) try: self.handler.handle(body, signature) except InvalidSignatureError: print( "Invalid signature. Please check your channel access token/channel secret." ) abort(400) return "OK" def on_command(self, cmd): command = f"{self.prefix}{cmd}" def decorate(function): self.commands[command] = function return decorate def parse_command(self, ctx, cmd, *args) -> bool: if cmd in self.commands: self.commands[cmd](ctx, *args) return True return False def on_message(self, event): ctx = Context(event, self.lineapi) splitted = shlex.split(event.message.text) self.parse_command(ctx, *splitted) return def on_follow(self, event): pass def on_unfollow(self, event): pass def on_join(self, event): pass def on_leave(self, event): pass def _pre_start(self): @self.handler.add(MessageEvent, message=TextMessage) def on_message(event): self.on_message(event) @self.handler.add(FollowEvent) def on_follow(event): self.on_follow(event) @self.handler.add(UnfollowEvent) def on_unfollow(event): self.on_unfollow(event) @self.handler.add(JoinEvent) def on_join(event): self.on_join(event) @self.handler.add(LeaveEvent) def on_leave(event): self.on_leave(event)
class LINE(object): @staticmethod def get_key(event, message=None): if message is None: return event.__name__ else: return event.__name__ + '_' + message.__name__ def set_handler(self, callback, event, message=None): key = self.get_key(event, message=message) self.handler._handlers[key] = callback def __init__(self, app, api_token, secret, path='/line-callback', name='line_callback'): self.app = app self.app.add_url_rule(path, name, self.callback, methods=['POST']) self.bot_api = LineBotApi(api_token) self.handler = WebhookHandler(secret) self.set_handler(self.got_text, MessageEvent, message=TextMessage) self.text_message = None self.command_call = {} self.unknown_command = "Ummm... This command not found." self.text_message = "Umm... This bot no reply feature." self._stop = True def Command(self, command, func, pass_args=False): self.command_call[command] = {} self.command_call[command]['call'] = func self.command_call[command]['args'] = pass_args def Start(self): self._stop = False def Stop(self): self._stop = True def Push(self, to, data, type='text'): if type == 'text': self.bot_api.push_message(to, TextSendMessage(text=data)) def got_text(self, event): cmd = re_match(r'^\/(\w+)', event.message.text) if cmd: cmd = cmd.group(1) if cmd in self.command_call: if type(self.command_call[cmd]['call']) is str: text = self.command_call[cmd]['call'] self.bot_api.reply_message(event.reply_token, TextSendMessage(text=text)) elif self.command_call[cmd]['args']: if ' ' in event.message.text: args = event.message.text.split() del args[0] msg = Message('LINE') msg.setEvent(bot=self.bot_api, event=event, args=args, type='command') self.command_call[cmd]['call'](msg) else: msg = Message('LINE') msg.setEvent(bot=self.bot_api, event=event, args=[], type='command') self.command_call[cmd]['call'](msg) else: msg = Message('LINE') msg.setEvent(bot=self.bot_api, event=event, type='command') self.command_call[cmd]['call'](msg) elif event.source.type not in ('room', 'group', 'supergroup'): text = self.unknown_command self.bot_api.reply_message(event.reply_token, TextSendMessage(text=text)) else: if type(self.text_message) in (str, unicode): self.bot_api.reply_message( event.reply_token, TextSendMessage(text=self.text_message)) else: msg = Message('LINE') msg.setEvent(bot=self.bot_api, event=event, type='text') self.text_message(msg) def callback(self): if self._stop: abort(404) signature = request.headers['X-Line-Signature'] body = request.get_data(as_text=True) self.app.logger.info("Request body: " + body) try: self.handler.handle(body, signature) except InvalidSignatureError: abort(400) return 'OK'
class TestWebhookHandler(unittest.TestCase): def setUp(self): self.handler = WebhookHandler('channel_secret') self.calls = [] @self.handler.add(MessageEvent, message=TextMessage) def message_text(event): self.calls.append('1 ' + event.type + '_' + event.message.type) @self.handler.add( MessageEvent, message=(ImageMessage, VideoMessage, AudioMessage)) def message_content(event): self.calls.append('2 ' + event.type + '_' + event.message.type) @self.handler.add(MessageEvent, message=StickerMessage) def message_sticker(event): self.calls.append('3 ' + event.type + '_' + event.message.type) @self.handler.add(MessageEvent) def message(event): self.calls.append(event.type + '_' + event.message.type) @self.handler.add(FollowEvent) def follow(event): self.calls.append('4 ' + event.type) @self.handler.add(JoinEvent) def join(event): self.calls.append('5 ' + event.type) @self.handler.add(PostbackEvent) def postback(event): self.calls.append('6 ' + event.type) @self.handler.add(BeaconEvent) def beacon(event): self.calls.append('7 ' + event.type) @self.handler.default() def default(event): self.calls.append('default ' + event.type) def test_handler(self): file_dir = os.path.dirname(__file__) webhook_sample_json_path = os.path.join(file_dir, 'text', 'webhook.json') with open(webhook_sample_json_path) as fp: body = fp.read() # mock self.handler.parser.signature_validator.validate = lambda a, b: True self.handler.handle(body, 'signature') self.assertEqual(self.calls[0], '1 message_text') self.assertEqual(self.calls[1], '2 message_image') self.assertEqual(self.calls[2], '2 message_video') self.assertEqual(self.calls[3], '2 message_audio') self.assertEqual(self.calls[4], 'message_location') self.assertEqual(self.calls[5], '3 message_sticker') self.assertEqual(self.calls[6], '4 follow') self.assertEqual(self.calls[7], 'default unfollow') self.assertEqual(self.calls[8], '5 join') self.assertEqual(self.calls[9], 'default leave') self.assertEqual(self.calls[10], '6 postback') self.assertEqual(self.calls[11], '7 beacon') self.assertEqual(self.calls[12], '7 beacon') self.assertEqual(self.calls[13], '1 message_text') self.assertEqual(self.calls[14], '1 message_text') self.assertEqual(self.calls[15], '6 postback') self.assertEqual(self.calls[16], '6 postback') self.assertEqual(self.calls[17], '6 postback')
class BotService: def __init__(self): self.line_bot_api = LineBotApi( os.environ.get('YOUR_CHANNEL_ACCESS_TOKEN', '')) self.handler = WebhookHandler(os.environ.get('YOUR_CHANNEL_SECRET', '')) self.lending_use_case = LendingUseCase( LendingRepositoryImpl(UserRepositoryImpl())) self.slack_service = SlackService() @self.handler.add(MessageEvent, message=TextMessage) def handle_message(event: MessageEvent): request_text: str = event.message.text split_request_text = request_text.split() if len(split_request_text) is not 2: self._response_random(event.reply_token) return request_message, lending_id = split_request_text lending = self.lending_use_case.fetch_lending(lending_id) content = lending.content owner_name = lending.owner_name borrower_id = lending.borrower_id is_confirming_returned = lending.is_confirming_returned if not is_confirming_returned: self._response_random(event.reply_token) return if request_message == 'はい': self.line_bot_api.reply_message( event.reply_token, TextSendMessage(text='返ってきてよかったチュン!')) self.line_bot_api.push_message( borrower_id, TextSendMessage( text=f"「{owner_name}」さんから借りた「{content}」返してくれてありがとチュン!") ) self.lending_use_case.register_return_lending(lending_id) self.lending_use_case.finish_confirming_returned(lending_id) elif request_message == 'いいえ': self.line_bot_api.reply_message(event.reply_token, [ TextSendMessage(text='悲しいチュン...'), TextSendMessage(text='早く返してって言ってくるチュン!') ]) self.line_bot_api.push_message( borrower_id, TextSendMessage( text=f"「{owner_name}」さんに借りた「{content}」返して欲しいチュン\n\n" f"もし既に返してたら申し訳ないチュン...\n" f"「{owner_name}」さんに通知解除してって言って欲しいチュン...")) self.lending_use_case.finish_confirming_returned(lending_id) else: self.line_bot_api.reply_message( event.reply_token, TextSendMessage(text='上のボタンをタップして答えて欲しいチュン。')) def _response_random(self, reply_token: str): self.line_bot_api.reply_message( reply_token, TextSendMessage(text=random.choice(random_messages))) def handle_hook(self, body, signature): self.handler.handle(body, signature) def send_message_for_deadline_lendings(self, notify: bool = True): deadline_lending_list = self.lending_use_case.fetch_deadline_lending_list( ) if notify: list_len = len(deadline_lending_list) if list_len == 0: message = '今日が期限の貸借りはなかったチュン!\nみんなちゃんと返しててえらいチュン!' else: message = f"今日が締め切りの貸借りは{list_len}件だチュン!みんな返してもらえてるか確認してくるチュン!" webhook_username = '******' try: self.slack_service.notify(webhook_username, message) except Exception as e: print(e) with open(f"{root_path}/src/api/service/confirm_message.json") as f: base_contents = json.load(f) for owner_id, lendings in deadline_lending_list.items(): messages = [] for lending in lendings: self.lending_use_case.start_confirming_returned( lending.lending_id) contents = base_contents.copy() message = f"「{lending.borrower_name}」さんに貸した「{lending.content}」返ってきたチュン?" contents['body']['contents'][0]['text'] = message # コールバックのエンドポイントに送信されるデータの末尾に、空白区切りで貸借りidを追加する contents['footer']['contents'][0]['action'][ 'text'] += f" {lending.lending_id}" contents['footer']['contents'][1]['action'][ 'text'] += f" {lending.lending_id}" messages.append( FlexSendMessage(alt_text=message, contents=contents)) self.line_bot_api.push_message(owner_id, messages)