def test_client_send(self, mock_post): mock_post.return_value.status_code = 200 mock_post.return_value.json.return_value = { 'success': True } messenger = MessengerClient(access_token='1234') recipient = messages.Recipient(recipient_id='123') message = messages.Message(text='Hello World') request = messages.MessageRequest(recipient, message) messenger.send(request) mock_post.assert_called_with( 'https://graph.facebook.com/v2.6/me/messages', json={ "message": {"text": "Hello World"}, "recipient": {"id": "123"} }, params={'access_token': '1234'} )
class MessengerBot(IntegrationBot): """ Facebook Messenger integration. Permabots only uses Page Access Token but webhook is not set. It mus be set manually in Facebook dev platform using UUID generated as id of the messenger bot after creation in Permabots. This bot is used to Verify Token and generate url https://domain/processing/messengerbot/permabots_messenger_bot_id/ Read Messenger documentation `<https://developers.facebook.com/docs/messenger-platform/quickstart>` _. """ token = models.CharField(_('Messenger Token'), max_length=512, db_index=True) class Meta: verbose_name = _('Messenger Bot') verbose_name_plural = _('Messenger Bots') def __init__(self, *args, **kwargs): super(MessengerBot, self).__init__(*args, **kwargs) self._bot = None self.webhook = False if self.token: self.init_bot() def __str__(self): return "%s" % self.token def __repr__(self): return "(%s, %s)" % (self.id, self.token) def init_bot(self): self._bot = MessengerClient(self.token) def set_webhook(self, url): # Url is set in facebook dashboard. Just subscribe self._bot.subscribe_app() @property def hook_url(self): return 'permabots:messengerbot' @property def hook_id(self): return str(self.id) @property def null_url(self): # not used return "https://example.com" @property def identity(self): return 'messenger' def message_text(self, message): return message.data def get_chat_state(self, message): try: return MessengerChatState.objects.select_related('state').get( chat=message.sender, state__bot=self.bot) except MessengerChatState.DoesNotExist: return None def build_keyboard(self, keyboard): def traverse(o, tree_types=(list, tuple)): if isinstance(o, tree_types): for value in o: for subvalue in traverse(value, tree_types): yield subvalue else: yield o built_keyboard = None if keyboard: # same payload as title built_keyboard = [ PostbackButton(element[0:20], element) for element in traverse(ast.literal_eval(keyboard)) ] return built_keyboard def create_chat_state(self, message, target_state, context): MessengerChatState.objects.create(chat=message.sender, state=target_state, ctx=context) def get_chat_id(self, message): return message.sender def send_message(self, chat_id, text, keyboard, reply_message=None, user=None): texts = text.strip().split('\\n') msgs = [] for txt in texts: for chunk in textwrap.wrap(txt, 320): msgs.append(messages.Message(text=chunk)) if keyboard: if len(msgs[-1].text) <= 45: title = msgs.pop().text else: new_texts = textwrap.wrap(msgs[-1].text, 45) msgs[-1].text = " ".join(new_texts[:-1]) title = new_texts[-1] elements = [] for chunk_buttons, last in self.batch(keyboard[0:30], 3): elements.append(Element(title=title, buttons=chunk_buttons)) generic_template = GenericTemplate(elements) attachment = TemplateAttachment(generic_template) msgs.append(messages.Message(attachment=attachment)) for msg in msgs: try: logger.debug("Message to send:(%s)" % msg.to_dict()) recipient = messages.Recipient(recipient_id=chat_id) self._bot.send(messages.MessageRequest(recipient, msg)) logger.debug("Message sent OK:(%s)" % msg.to_dict()) except: exctype, value = sys.exc_info()[:2] logger.error("Error trying to send message:(%s): %s:%s" % (msg.to_dict(), exctype, value))
class MessengerBot(IntegrationBot): """ Facebook Messenger integration. Permabots only uses Page Access Token but webhook is not set. It mus be set manually in Facebook dev platform using UUID generated as id of the messenger bot after creation in Permabots. This bot is used to Verify Token and generate url https://domain/processing/messengerbot/permabots_messenger_bot_id/ Read Messenger documentation `<https://developers.facebook.com/docs/messenger-platform/quickstart>` _. """ token = models.CharField(_('Messenger Token'), max_length=512, db_index=True) class Meta: verbose_name = _('Messenger Bot') verbose_name_plural = _('Messenger Bots') def __init__(self, *args, **kwargs): super(MessengerBot, self).__init__(*args, **kwargs) self._bot = None self.webhook = False if self.token: self.init_bot() def __str__(self): return "%s" % self.token def __repr__(self): return "(%s, %s)" % (self.id, self.token) def init_bot(self): self._bot = MessengerClient(self.token) def set_webhook(self, url): # Url is set in facebook dashboard. Just subscribe self._bot.subscribe_app() @property def hook_url(self): return 'permabots:messengerbot' @property def hook_id(self): return str(self.id) @property def null_url(self): # not used return "https://example.com" @property def identity(self): return 'messenger' def message_text(self, message): return message.data def get_chat_state(self, message): try: return MessengerChatState.objects.select_related('state').get(chat=message.sender, state__bot=self.bot) except MessengerChatState.DoesNotExist: return None def build_keyboard(self, keyboard): def traverse(o, tree_types=(list, tuple)): if isinstance(o, tree_types): for value in o: for subvalue in traverse(value, tree_types): yield subvalue else: yield o built_keyboard = None if keyboard: # same payload as title built_keyboard = [PostbackButton(element[0:20], element) for element in traverse(ast.literal_eval(keyboard))] return built_keyboard def create_chat_state(self, message, target_state, context): MessengerChatState.objects.create(chat=message.sender, state=target_state, ctx=context) def get_chat_id(self, message): return message.sender def send_message(self, chat_id, text, keyboard, reply_message=None, user=None): texts = text.strip().split('\\n') msgs = [] for txt in texts: for chunk in textwrap.wrap(txt, 320): msgs.append(messages.Message(text=chunk)) if keyboard: if len(msgs[-1].text) <= 45: title = msgs.pop().text else: new_texts = textwrap.wrap(msgs[-1].text, 45) msgs[-1].text = " ".join(new_texts[:-1]) title = new_texts[-1] elements = [] for chunk_buttons, last in self.batch(keyboard[0:30], 3): elements.append(Element(title=title, buttons=chunk_buttons)) generic_template = GenericTemplate(elements) attachment = TemplateAttachment(generic_template) msgs.append(messages.Message(attachment=attachment)) for msg in msgs: try: logger.debug("Message to send:(%s)" % msg.to_dict()) recipient = messages.Recipient(recipient_id=chat_id) self._bot.send(messages.MessageRequest(recipient, msg)) logger.debug("Message sent OK:(%s)" % msg.to_dict()) except: exctype, value = sys.exc_info()[:2] logger.error("Error trying to send message:(%s): %s:%s" % (msg.to_dict(), exctype, value))
class Replies(object): def __init__(self, access_token, recipient_id): self.access_token = access_token self.recipient_id = recipient_id self.messenger = MessengerClient(access_token=access_token) @property def recipient(self): return messages.Recipient(recipient_id=self.recipient_id) def reply_msg(self, text): message = messages.Message(text=text) request = messages.MessageRequest(self.recipient, message) self.messenger.send(request) def ask_where(self): self.reply_msg('Xin chào! Bạn muốn ăn ở đâu?') def give_suggestions(self, location, negations): text = 'kết quả từ {district} nè'.format(district=location) self.reply_msg(text) results = quanbot.quan.Quan.search(location, negations) if results: elements = list(map(self._quan_element, results)) self._send_carousel(elements) return True else: self.reply_msg("Không tìm thành công thì restart") return False def failed_read_location(self): self.reply_msg('Vui lòng viết lại') def say_restarting(self): self.reply_msg('Rồi, hãy thử một lần nữa nha') def _quan_element(self, qd): web_button = elements.WebUrlButton( title='xem trên Foody.vn', url=qd['URL'], ) postback_button = elements.PostbackButton( title="Không " + qd['maindish'], payload="Không " + qd['maindish'], ) element = elements.Element( title=qd['Name'], item_url=qd['URL'], image_url=qd['Pic'], subtitle=qd['dish'], buttons=[ # web_button, postback_button, ], ) return element def _send_carousel(self, elements): generic_template = templates.GenericTemplate( elements=elements ) attachment = attachments.TemplateAttachment(template=generic_template) message = messages.Message(attachment=attachment) request = messages.MessageRequest(self.recipient, message) self.messenger.send(request)