From f9245cdfed84aa7acb6ff857553e7d370bb99441 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Mon, 24 Sep 2018 20:54:25 +0200 Subject: [PATCH 01/14] New model and `Message` attribute New `QuickReply` model and `quick_replies` attribute of `Message` model. --- fbchat/models.py | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/fbchat/models.py b/fbchat/models.py index cb4f678..6145e0b 100644 --- a/fbchat/models.py +++ b/fbchat/models.py @@ -188,8 +188,10 @@ class Message(object): sticker = None #: A list of attachments attachments = None + #: A list of :class:`QuickReply` + quick_replies = None - def __init__(self, text=None, mentions=None, emoji_size=None, sticker=None, attachments=None): + def __init__(self, text=None, mentions=None, emoji_size=None, sticker=None, attachments=None, quick_replies=None): """Represents a Facebook message""" self.text = text if mentions is None: @@ -200,6 +202,9 @@ class Message(object): if attachments is None: attachments = [] self.attachments = attachments + if quick_replies is None: + quick_replies = [] + self.quick_replies = quick_replies self.reactions = {} def __repr__(self): @@ -439,6 +444,31 @@ class Mention(object): def __unicode__(self): return ''.format(self.thread_id, self.offset, self.length) +class QuickReply(object): + #: Title of the quick reply + title = None + #: URL of the quick reply image (optional) + image_url = None + #: Custom identifier of the quick reply + payload = None + #: Additional data + data = None + #: Whether it's a response for a quick reply + is_response = None + + def __init__(self, title, image_url=None, payload=None, data=None): + """Represents a quick reply""" + self.title = title + self.image_url = image_url + self.payload = payload + self.data = data + + def __repr__(self): + return self.__unicode__() + + def __unicode__(self): + return ''.format(self.title, self.payload) + class Poll(object): #: ID of the poll uid = None From 531a5b77d03f835cc1d607231f36001e208740cc Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Mon, 24 Sep 2018 20:57:19 +0200 Subject: [PATCH 02/14] GraphQL method for quick replies --- fbchat/graphql.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fbchat/graphql.py b/fbchat/graphql.py index f023a16..877b8d6 100644 --- a/fbchat/graphql.py +++ b/fbchat/graphql.py @@ -193,6 +193,16 @@ def graphql_to_plan(a): rtn.invited = [m.get('node').get('id') for m in guests if m.get('guest_list_state') == "INVITED"] return rtn +def graphql_to_quick_reply(q, is_response=None): + rtn = QuickReply( + title=q.get('title'), + image_url=q.get('image_url'), + payload=q.get('payload'), + data=q.get('data'), + ) + rtn.is_response = is_response + return rtn + def graphql_to_message(message): if message.get('message_sender') is None: message['message_sender'] = {} @@ -214,6 +224,12 @@ def graphql_to_message(message): rtn.attachments = [graphql_to_attachment(attachment) for attachment in message['blob_attachments']] # TODO: This is still missing parsing: # message.get('extensible_attachment') + if message.get('platform_xmd_encoded'): + quick_replies = json.loads(message['platform_xmd_encoded']).get('quick_replies') + if isinstance(quick_replies, list): + rtn.quick_replies = [graphql_to_quick_reply(q, is_response=False) for q in quick_replies] + elif isinstance(quick_replies, dict): + rtn.quick_replies = [graphql_to_quick_reply(quick_replies, is_response=True)] return rtn def graphql_to_user(user): From 5f2c318baf53f39eb31e9f13f51a767186878e99 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Mon, 24 Sep 2018 21:04:21 +0200 Subject: [PATCH 03/14] Sending quick replies --- fbchat/client.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fbchat/client.py b/fbchat/client.py index 69c858d..17587f9 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -1045,6 +1045,18 @@ class Client(object): if message.sticker: data['sticker_id'] = message.sticker.uid + if message.quick_replies: + xmd = {"quick_replies": []} + for quick_reply in message.quick_replies: + xmd["quick_replies"].append({ + "content_type": "text", + "title": quick_reply.title, + "payload": quick_reply.payload, + "image_url": quick_reply.image_url, + "data": quick_reply.data, + }) + data['platform_xmd'] = json.dumps(xmd) + return data def _doSendRequest(self, data, get_thread_id=False): From f185e44f932fd2e28d2d7f6637f5198c980837c3 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Tue, 25 Sep 2018 17:59:16 +0200 Subject: [PATCH 04/14] Update models.py --- fbchat/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fbchat/models.py b/fbchat/models.py index 6145e0b..4ec9fd5 100644 --- a/fbchat/models.py +++ b/fbchat/models.py @@ -456,12 +456,13 @@ class QuickReply(object): #: Whether it's a response for a quick reply is_response = None - def __init__(self, title, image_url=None, payload=None, data=None): + def __init__(self, title, image_url=None, payload=None, data=None, is_response=False): """Represents a quick reply""" self.title = title self.image_url = image_url self.payload = payload self.data = data + self.is_response = is_response def __repr__(self): return self.__unicode__() From 492465a525a6ae13d055e03a816bdf74a0139459 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Tue, 25 Sep 2018 18:00:44 +0200 Subject: [PATCH 05/14] Update graphql.py --- fbchat/graphql.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fbchat/graphql.py b/fbchat/graphql.py index 877b8d6..066ee31 100644 --- a/fbchat/graphql.py +++ b/fbchat/graphql.py @@ -193,14 +193,14 @@ def graphql_to_plan(a): rtn.invited = [m.get('node').get('id') for m in guests if m.get('guest_list_state') == "INVITED"] return rtn -def graphql_to_quick_reply(q, is_response=None): +def graphql_to_quick_reply(q, is_response=False): rtn = QuickReply( title=q.get('title'), image_url=q.get('image_url'), payload=q.get('payload'), data=q.get('data'), + is_response=is_response, ) - rtn.is_response = is_response return rtn def graphql_to_message(message): @@ -227,7 +227,7 @@ def graphql_to_message(message): if message.get('platform_xmd_encoded'): quick_replies = json.loads(message['platform_xmd_encoded']).get('quick_replies') if isinstance(quick_replies, list): - rtn.quick_replies = [graphql_to_quick_reply(q, is_response=False) for q in quick_replies] + rtn.quick_replies = [graphql_to_quick_reply(q) for q in quick_replies] elif isinstance(quick_replies, dict): rtn.quick_replies = [graphql_to_quick_reply(quick_replies, is_response=True)] return rtn From be968e0caaa8a98ce47886604070d461cfe74436 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Sun, 9 Dec 2018 00:32:44 +0100 Subject: [PATCH 06/14] New models for quick replies --- fbchat/models.py | 58 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/fbchat/models.py b/fbchat/models.py index 4ec9fd5..4546453 100644 --- a/fbchat/models.py +++ b/fbchat/models.py @@ -445,21 +445,18 @@ class Mention(object): return ''.format(self.thread_id, self.offset, self.length) class QuickReply(object): - #: Title of the quick reply - title = None - #: URL of the quick reply image (optional) - image_url = None - #: Custom identifier of the quick reply + #: Type of the quick reply + type = None + #: Payload of the quick reply payload = None #: Additional data data = None #: Whether it's a response for a quick reply is_response = None - def __init__(self, title, image_url=None, payload=None, data=None, is_response=False): + def __init__(self, _type=None, payload=None, data=None, is_response=False): """Represents a quick reply""" - self.title = title - self.image_url = image_url + self.type = _type self.payload = payload self.data = data self.is_response = is_response @@ -468,7 +465,44 @@ class QuickReply(object): return self.__unicode__() def __unicode__(self): - return ''.format(self.title, self.payload) + return ''.format(self.type, self.payload) + +class QuickReplyText(QuickReply): + #: Title of the quick reply + title = None + #: URL of the quick reply image (optional) + image_url = None + + def __init__(self, title=None, image_url=None, **kwargs): + """Represents a text quick reply""" + super(QuickReplyText, self).__init__(_type=QuickReplyType.TEXT, **kwargs) + self.title = title + self.image_url = image_url + +class QuickReplyLocation(QuickReply): + + def __init__(self, **kwargs): + """Represents a location quick reply""" + super(QuickReplyLocation, self).__init__(_type=QuickReplyType.LOCATION, **kwargs) + self.is_response = False + +class QuickReplyPhoneNumber(QuickReply): + #: URL of the quick reply image (optional) + image_url = None + + def __init__(self, image_url=None, **kwargs): + """Represents a phone number quick reply""" + super(QuickReplyPhoneNumber, self).__init__(_type=QuickReplyType.PHONE_NUMBER, **kwargs) + self.image_url = image_url + +class QuickReplyEmail(QuickReply): + #: URL of the quick reply image (optional) + image_url = None + + def __init__(self, image_url=None, **kwargs): + """Represents an email quick reply""" + super(QuickReplyEmail, self).__init__(_type=QuickReplyType.EMAIL, **kwargs) + self.image_url = image_url class Poll(object): #: ID of the poll @@ -557,6 +591,12 @@ class Enum(enum.Enum): # For documentation: return '{}.{}'.format(type(self).__name__, self.name) +class QuickReplyType(Enum): + TEXT = 'TEXT' + LOCATION = 'LOCATION' + PHONE_NUMBER = 'USER_PHONE_NUMBER' + EMAIL = 'USER_EMAIL' + class ThreadType(Enum): """Used to specify what type of Facebook thread is being used. See :ref:`intro_threads` for more info""" USER = 1 From c089298f467334f7bde3c9622c516087638206cd Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Sun, 9 Dec 2018 00:57:58 +0100 Subject: [PATCH 07/14] Sending new quick replies --- fbchat/client.py | 16 +++++++++------- fbchat/models.py | 6 +++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index 17587f9..3b6a7a5 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -1048,13 +1048,15 @@ class Client(object): if message.quick_replies: xmd = {"quick_replies": []} for quick_reply in message.quick_replies: - xmd["quick_replies"].append({ - "content_type": "text", - "title": quick_reply.title, - "payload": quick_reply.payload, - "image_url": quick_reply.image_url, - "data": quick_reply.data, - }) + q = dict() + q["content_type"] = quick_reply.type.value.lower() + q["payload"] = quick_reply.payload + q["data"] = quick_reply.data + if isinstance(quick_reply, QuickReplyText): q["title"] = quick_reply.title + if not isinstance(quick_reply, QuickReplyLocation): q["image_url"] = quick_reply.image_url + xmd["quick_replies"].append(q) + if len(message.quick_replies) == 1 and message.quick_replies[0].is_response: + xmd["quick_replies"] = xmd["quick_replies"][0] data['platform_xmd'] = json.dumps(xmd) return data diff --git a/fbchat/models.py b/fbchat/models.py index 4546453..3bcddc3 100644 --- a/fbchat/models.py +++ b/fbchat/models.py @@ -482,7 +482,7 @@ class QuickReplyText(QuickReply): class QuickReplyLocation(QuickReply): def __init__(self, **kwargs): - """Represents a location quick reply""" + """Represents a location quick reply (Doesn't work on mobile)""" super(QuickReplyLocation, self).__init__(_type=QuickReplyType.LOCATION, **kwargs) self.is_response = False @@ -491,7 +491,7 @@ class QuickReplyPhoneNumber(QuickReply): image_url = None def __init__(self, image_url=None, **kwargs): - """Represents a phone number quick reply""" + """Represents a phone number quick reply (Doesn't work on mobile)""" super(QuickReplyPhoneNumber, self).__init__(_type=QuickReplyType.PHONE_NUMBER, **kwargs) self.image_url = image_url @@ -500,7 +500,7 @@ class QuickReplyEmail(QuickReply): image_url = None def __init__(self, image_url=None, **kwargs): - """Represents an email quick reply""" + """Represents an email quick reply (Doesn't work on mobile)""" super(QuickReplyEmail, self).__init__(_type=QuickReplyType.EMAIL, **kwargs) self.image_url = image_url From 5f9c357a1506859f1555659ac33e6d08a68cfb53 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Sun, 9 Dec 2018 01:07:33 +0100 Subject: [PATCH 08/14] Fixed graphql and added method for replying on quick replies --- fbchat/client.py | 13 +++++++++++++ fbchat/graphql.py | 22 +++++++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index 3b6a7a5..32c72b2 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -1130,6 +1130,19 @@ class Client(object): data['specific_to_list[0]'] = "fbid:{}".format(thread_id) return self._doSendRequest(data) + def quickReply(self, quick_reply, thread_id=None, thread_type=None): + """ + Replies to a chosen quick reply + + :param thread_id: User/Group ID to send to. See :ref:`intro_threads` + :param thread_type: See :ref:`intro_threads` + :type thread_type: models.ThreadType + :return: :ref:`Message ID ` of the sent message + :raises: FBchatException if request failed + """ + quick_reply.is_response = True + return self.send(Message(text=quick_reply.title, quick_replies=[quick_reply])) + def _upload(self, files): """ Uploads files to Facebook diff --git a/fbchat/graphql.py b/fbchat/graphql.py index 066ee31..397448b 100644 --- a/fbchat/graphql.py +++ b/fbchat/graphql.py @@ -194,13 +194,21 @@ def graphql_to_plan(a): return rtn def graphql_to_quick_reply(q, is_response=False): - rtn = QuickReply( - title=q.get('title'), - image_url=q.get('image_url'), - payload=q.get('payload'), - data=q.get('data'), - is_response=is_response, - ) + data = dict() + if q.get('title') is not None: data["title"] = q["title"] + if q.get('image_url') is not None: data["image_url"] = q["image_url"] + if q.get('payload') is not None: data["payload"] = q["payload"] + if q.get('data') is not None: data["data"] = q["data"] + data["is_response"] = is_response + _type = QuickReplyType(q.get('content_type').upper()) + if _type == QuickReplyType.TEXT: + rtn = QuickReplyText(**data) + elif _type == QuickReplyType.LOCATION: + rtn = QuickReplyLocation(**data) + elif _type == QuickReplyType.PHONE_NUMBER: + rtn = QuickReplyPhoneNumber(**data) + elif _type == QuickReplyType.EMAIL: + rtn = QuickReplyEmail(**data) return rtn def graphql_to_message(message): From edc33db9e83add6eb59151d656cc6ff1dc578d36 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Sun, 23 Dec 2018 14:36:26 +0100 Subject: [PATCH 09/14] Few fixes in quick replies --- fbchat/client.py | 7 ++++--- fbchat/graphql.py | 10 +++++----- fbchat/models.py | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index 32c72b2..7a16cf9 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -1052,8 +1052,8 @@ class Client(object): q["content_type"] = quick_reply.type.value.lower() q["payload"] = quick_reply.payload q["data"] = quick_reply.data - if isinstance(quick_reply, QuickReplyText): q["title"] = quick_reply.title - if not isinstance(quick_reply, QuickReplyLocation): q["image_url"] = quick_reply.image_url + if quick_reply.type == QuickReplyType.TEXT: q["title"] = quick_reply.title + if quick_reply.type is not QuickReplyType.LOCATION: q["image_url"] = quick_reply.image_url xmd["quick_replies"].append(q) if len(message.quick_replies) == 1 and message.quick_replies[0].is_response: xmd["quick_replies"] = xmd["quick_replies"][0] @@ -1141,7 +1141,8 @@ class Client(object): :raises: FBchatException if request failed """ quick_reply.is_response = True - return self.send(Message(text=quick_reply.title, quick_replies=[quick_reply])) + if quick_reply.type == QuickReplyType.TEXT: + return self.send(Message(text=quick_reply.title, quick_replies=[quick_reply])) def _upload(self, files): """ diff --git a/fbchat/graphql.py b/fbchat/graphql.py index 397448b..5b46362 100644 --- a/fbchat/graphql.py +++ b/fbchat/graphql.py @@ -195,13 +195,13 @@ def graphql_to_plan(a): def graphql_to_quick_reply(q, is_response=False): data = dict() - if q.get('title') is not None: data["title"] = q["title"] - if q.get('image_url') is not None: data["image_url"] = q["image_url"] - if q.get('payload') is not None: data["payload"] = q["payload"] - if q.get('data') is not None: data["data"] = q["data"] - data["is_response"] = is_response _type = QuickReplyType(q.get('content_type').upper()) + if q.get('payload'): data["payload"] = q["payload"] + if q.get('data'): data["data"] = q["data"] + if q.get('image_url') and _type is not QuickReplyType.LOCATION: data["image_url"] = q["image_url"] + data["is_response"] = is_response if _type == QuickReplyType.TEXT: + if q.get('title') is not None: data["title"] = q["title"] rtn = QuickReplyText(**data) elif _type == QuickReplyType.LOCATION: rtn = QuickReplyLocation(**data) diff --git a/fbchat/models.py b/fbchat/models.py index 3bcddc3..85779fe 100644 --- a/fbchat/models.py +++ b/fbchat/models.py @@ -465,7 +465,7 @@ class QuickReply(object): return self.__unicode__() def __unicode__(self): - return ''.format(self.type, self.payload) + return '<{}: payload={!r}>'.format(self.__class__.__name__, self.payload) class QuickReplyText(QuickReply): #: Title of the quick reply From 0d05d42f70ac416ce6ff1affbefb5b39830d5d4e Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Thu, 3 Jan 2019 22:54:47 +0100 Subject: [PATCH 10/14] getPhoneNumbers and getEmails methods --- fbchat/client.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/fbchat/client.py b/fbchat/client.py index 7a16cf9..121d24f 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -989,6 +989,30 @@ class Client(object): plan = graphql_to_plan(j["payload"]) return plan + def _getPrivateData(self): + j = self.graphql_request(GraphQL(doc_id='1868889766468115')) + return j['viewer'] + + def getPhoneNumbers(self): + """ + Fetches a list of user phone numbers. + + :return: List of phone numbers + :rtype: list + """ + data = self._getPrivateData() + return [j['phone_number']['universal_number'] for j in data['user']['all_phones']] + + def getEmails(self): + """ + Fetches a list of user emails. + + :return: List of emails + :rtype: list + """ + data = self._getPrivateData() + return [j['display_email'] for j in data['all_emails']] + """ END FETCH METHODS """ From 79ebf920ea75021c9a3579e338c6564476db10d5 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Thu, 3 Jan 2019 23:28:23 +0100 Subject: [PATCH 11/14] More on responding to quick replies --- fbchat/client.py | 15 ++++++++++++++- fbchat/models.py | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/fbchat/client.py b/fbchat/client.py index 121d24f..220e9be 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -1154,12 +1154,15 @@ class Client(object): data['specific_to_list[0]'] = "fbid:{}".format(thread_id) return self._doSendRequest(data) - def quickReply(self, quick_reply, thread_id=None, thread_type=None): + def quickReply(self, quick_reply, payload=None, thread_id=None, thread_type=None): """ Replies to a chosen quick reply + :param quick_reply: Quick reply to reply to + :param payload: Optional answer to the quick reply :param thread_id: User/Group ID to send to. See :ref:`intro_threads` :param thread_type: See :ref:`intro_threads` + :type quick_reply: models.QuickReply :type thread_type: models.ThreadType :return: :ref:`Message ID ` of the sent message :raises: FBchatException if request failed @@ -1167,6 +1170,16 @@ class Client(object): quick_reply.is_response = True if quick_reply.type == QuickReplyType.TEXT: return self.send(Message(text=quick_reply.title, quick_replies=[quick_reply])) + elif quick_reply.type == QuickReplyType.EMAIL: + if not payload: payload = self.getEmails()[0] + quick_reply.external_payload = quick_reply.payload + quick_reply.payload = payload + return self.send(Message(text=payload, quick_replies=[quick_reply])) + elif quick_reply.type == QuickReplyType.PHONE_NUMBER: + if not payload: payload = self.getPhoneNumbers()[0] + quick_reply.external_payload = quick_reply.payload + quick_reply.payload = payload + return self.send(Message(text=payload, quick_replies=[quick_reply])) def _upload(self, files): """ diff --git a/fbchat/models.py b/fbchat/models.py index 85779fe..cc02e8b 100644 --- a/fbchat/models.py +++ b/fbchat/models.py @@ -449,6 +449,8 @@ class QuickReply(object): type = None #: Payload of the quick reply payload = None + #: External payload for responses + external_payload = None #: Additional data data = None #: Whether it's a response for a quick reply From 7f6843df551d4339575158a0f2a81e84b3f7567a Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Sat, 5 Jan 2019 20:06:28 +0100 Subject: [PATCH 12/14] Better quick reply types --- fbchat/client.py | 14 ++++++++------ fbchat/graphql.py | 12 ++++++------ fbchat/models.py | 27 +++++++++++++-------------- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index e64e809..6f1bac8 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -1068,11 +1068,13 @@ class Client(object): xmd = {"quick_replies": []} for quick_reply in message.quick_replies: q = dict() - q["content_type"] = quick_reply.type.value.lower() + q["content_type"] = quick_reply._type q["payload"] = quick_reply.payload + q["external_payload"] = quick_reply.external_payload q["data"] = quick_reply.data - if quick_reply.type == QuickReplyType.TEXT: q["title"] = quick_reply.title - if quick_reply.type is not QuickReplyType.LOCATION: q["image_url"] = quick_reply.image_url + if quick_reply.is_response: q["ignore_for_webhook"] = False + if quick_reply._type == QuickReplyText._type: q["title"] = quick_reply.title + if quick_reply._type is not QuickReplyLocation._type: q["image_url"] = quick_reply.image_url xmd["quick_replies"].append(q) if len(message.quick_replies) == 1 and message.quick_replies[0].is_response: xmd["quick_replies"] = xmd["quick_replies"][0] @@ -1163,14 +1165,14 @@ class Client(object): :raises: FBchatException if request failed """ quick_reply.is_response = True - if quick_reply.type == QuickReplyType.TEXT: + if isinstance(quick_reply, QuickReplyText): return self.send(Message(text=quick_reply.title, quick_replies=[quick_reply])) - elif quick_reply.type == QuickReplyType.EMAIL: + elif isinstance(quick_reply, QuickReplyEmail): if not payload: payload = self.getEmails()[0] quick_reply.external_payload = quick_reply.payload quick_reply.payload = payload return self.send(Message(text=payload, quick_replies=[quick_reply])) - elif quick_reply.type == QuickReplyType.PHONE_NUMBER: + elif isinstance(quick_reply, QuickReplyPhoneNumber): if not payload: payload = self.getPhoneNumbers()[0] quick_reply.external_payload = quick_reply.payload quick_reply.payload = payload diff --git a/fbchat/graphql.py b/fbchat/graphql.py index 20b658c..7e46d2c 100644 --- a/fbchat/graphql.py +++ b/fbchat/graphql.py @@ -270,19 +270,19 @@ def graphql_to_plan(a): def graphql_to_quick_reply(q, is_response=False): data = dict() - _type = QuickReplyType(q.get('content_type').upper()) + _type = q.get('content_type').lower() if q.get('payload'): data["payload"] = q["payload"] if q.get('data'): data["data"] = q["data"] - if q.get('image_url') and _type is not QuickReplyType.LOCATION: data["image_url"] = q["image_url"] + if q.get('image_url') and _type is not QuickReplyLocation._type: data["image_url"] = q["image_url"] data["is_response"] = is_response - if _type == QuickReplyType.TEXT: + if _type == QuickReplyText._type: if q.get('title') is not None: data["title"] = q["title"] rtn = QuickReplyText(**data) - elif _type == QuickReplyType.LOCATION: + elif _type == QuickReplyLocation._type: rtn = QuickReplyLocation(**data) - elif _type == QuickReplyType.PHONE_NUMBER: + elif _type == QuickReplyPhoneNumber._type: rtn = QuickReplyPhoneNumber(**data) - elif _type == QuickReplyType.EMAIL: + elif _type == QuickReplyEmail._type: rtn = QuickReplyEmail(**data) return rtn diff --git a/fbchat/models.py b/fbchat/models.py index 16c6c36..c636f86 100644 --- a/fbchat/models.py +++ b/fbchat/models.py @@ -527,8 +527,6 @@ class Mention(object): return ''.format(self.thread_id, self.offset, self.length) class QuickReply(object): - #: Type of the quick reply - type = None #: Payload of the quick reply payload = None #: External payload for responses @@ -538,9 +536,8 @@ class QuickReply(object): #: Whether it's a response for a quick reply is_response = None - def __init__(self, _type=None, payload=None, data=None, is_response=False): + def __init__(self, payload=None, data=None, is_response=False): """Represents a quick reply""" - self.type = _type self.payload = payload self.data = data self.is_response = is_response @@ -556,36 +553,44 @@ class QuickReplyText(QuickReply): title = None #: URL of the quick reply image (optional) image_url = None + #: Type of the quick reply + _type = "text" def __init__(self, title=None, image_url=None, **kwargs): """Represents a text quick reply""" - super(QuickReplyText, self).__init__(_type=QuickReplyType.TEXT, **kwargs) + super(QuickReplyText, self).__init__(**kwargs) self.title = title self.image_url = image_url class QuickReplyLocation(QuickReply): + #: Type of the quick reply + _type = "location" def __init__(self, **kwargs): """Represents a location quick reply (Doesn't work on mobile)""" - super(QuickReplyLocation, self).__init__(_type=QuickReplyType.LOCATION, **kwargs) + super(QuickReplyLocation, self).__init__(**kwargs) self.is_response = False class QuickReplyPhoneNumber(QuickReply): #: URL of the quick reply image (optional) image_url = None + #: Type of the quick reply + _type = "user_phone_number" def __init__(self, image_url=None, **kwargs): """Represents a phone number quick reply (Doesn't work on mobile)""" - super(QuickReplyPhoneNumber, self).__init__(_type=QuickReplyType.PHONE_NUMBER, **kwargs) + super(QuickReplyPhoneNumber, self).__init__(**kwargs) self.image_url = image_url class QuickReplyEmail(QuickReply): #: URL of the quick reply image (optional) image_url = None + #: Type of the quick reply + _type = "user_email" def __init__(self, image_url=None, **kwargs): """Represents an email quick reply (Doesn't work on mobile)""" - super(QuickReplyEmail, self).__init__(_type=QuickReplyType.EMAIL, **kwargs) + super(QuickReplyEmail, self).__init__(**kwargs) self.image_url = image_url class Poll(object): @@ -675,12 +680,6 @@ class Enum(enum.Enum): # For documentation: return '{}.{}'.format(type(self).__name__, self.name) -class QuickReplyType(Enum): - TEXT = 'TEXT' - LOCATION = 'LOCATION' - PHONE_NUMBER = 'USER_PHONE_NUMBER' - EMAIL = 'USER_EMAIL' - class ThreadType(Enum): """Used to specify what type of Facebook thread is being used. See :ref:`intro_threads` for more info""" USER = 1 From a367aa0b3113916d433995e71ce6b2df5f9c4be6 Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Sat, 5 Jan 2019 20:40:45 +0100 Subject: [PATCH 13/14] Replying on location quick replies --- fbchat/client.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fbchat/client.py b/fbchat/client.py index 6f1bac8..5f89244 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -1167,6 +1167,9 @@ class Client(object): quick_reply.is_response = True if isinstance(quick_reply, QuickReplyText): return self.send(Message(text=quick_reply.title, quick_replies=[quick_reply])) + elif isinstance(quick_reply, QuickReplyLocation): + if not isinstance(payload, LocationAttachment): raise ValueError("Payload must be an instance of `fbchat.models.LocationAttachment`") + return self.sendLocation(payload, thread_id=thread_id, thread_type=thread_type) elif isinstance(quick_reply, QuickReplyEmail): if not payload: payload = self.getEmails()[0] quick_reply.external_payload = quick_reply.payload From 27ffba3b149c4a5a9a00efed101a48e4c141c007 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 31 Jan 2019 19:21:52 +0100 Subject: [PATCH 14/14] Fix a few isinstance checks --- fbchat/client.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index 5f89244..4d0cce9 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -1072,9 +1072,12 @@ class Client(object): q["payload"] = quick_reply.payload q["external_payload"] = quick_reply.external_payload q["data"] = quick_reply.data - if quick_reply.is_response: q["ignore_for_webhook"] = False - if quick_reply._type == QuickReplyText._type: q["title"] = quick_reply.title - if quick_reply._type is not QuickReplyLocation._type: q["image_url"] = quick_reply.image_url + if quick_reply.is_response: + q["ignore_for_webhook"] = False + if isinstance(quick_reply, QuickReplyText): + q["title"] = quick_reply.title + if not isinstance(quick_reply, QuickReplyLocation): + q["image_url"] = quick_reply.image_url xmd["quick_replies"].append(q) if len(message.quick_replies) == 1 and message.quick_replies[0].is_response: xmd["quick_replies"] = xmd["quick_replies"][0]