Merge pull request #342 from kapi2289/quick_replies
[Feature] Quick replies
This commit is contained in:
@@ -984,6 +984,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
|
||||
"""
|
||||
@@ -1040,6 +1064,25 @@ 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:
|
||||
q = dict()
|
||||
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.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]
|
||||
data['platform_xmd'] = json.dumps(xmd)
|
||||
|
||||
return data
|
||||
|
||||
def _doSendRequest(self, data, get_thread_id=False):
|
||||
@@ -1111,6 +1154,36 @@ class Client(object):
|
||||
data['specific_to_list[0]'] = "fbid:{}".format(thread_id)
|
||||
return self._doSendRequest(data)
|
||||
|
||||
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 <intro_message_ids>` of the sent message
|
||||
:raises: FBchatException if request failed
|
||||
"""
|
||||
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
|
||||
quick_reply.payload = payload
|
||||
return self.send(Message(text=payload, quick_replies=[quick_reply]))
|
||||
elif isinstance(quick_reply, QuickReplyPhoneNumber):
|
||||
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 unsend(self, mid):
|
||||
"""
|
||||
Unsends a message (removes for everyone)
|
||||
|
@@ -267,6 +267,24 @@ 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=False):
|
||||
data = dict()
|
||||
_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 QuickReplyLocation._type: data["image_url"] = q["image_url"]
|
||||
data["is_response"] = is_response
|
||||
if _type == QuickReplyText._type:
|
||||
if q.get('title') is not None: data["title"] = q["title"]
|
||||
rtn = QuickReplyText(**data)
|
||||
elif _type == QuickReplyLocation._type:
|
||||
rtn = QuickReplyLocation(**data)
|
||||
elif _type == QuickReplyPhoneNumber._type:
|
||||
rtn = QuickReplyPhoneNumber(**data)
|
||||
elif _type == QuickReplyEmail._type:
|
||||
rtn = QuickReplyEmail(**data)
|
||||
return rtn
|
||||
|
||||
def graphql_to_message(message):
|
||||
if message.get('message_sender') is None:
|
||||
message['message_sender'] = {}
|
||||
@@ -290,6 +308,12 @@ def graphql_to_message(message):
|
||||
}
|
||||
if message.get('blob_attachments') is not None:
|
||||
rtn.attachments = [graphql_to_attachment(attachment) for attachment in message['blob_attachments']]
|
||||
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) for q in quick_replies]
|
||||
elif isinstance(quick_replies, dict):
|
||||
rtn.quick_replies = [graphql_to_quick_reply(quick_replies, is_response=True)]
|
||||
if message.get('extensible_attachment') is not None:
|
||||
attachment = graphql_to_extensible_attachment(message['extensible_attachment'])
|
||||
if isinstance(attachment, UnsentMessage):
|
||||
|
@@ -190,10 +190,12 @@ class Message(object):
|
||||
sticker = None
|
||||
#: A list of attachments
|
||||
attachments = None
|
||||
#: A list of :class:`QuickReply`
|
||||
quick_replies = None
|
||||
#: Whether the message is unsent (deleted for everyone)
|
||||
unsent = 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:
|
||||
@@ -204,6 +206,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 = {}
|
||||
self.read_by = []
|
||||
self.deleted = False
|
||||
@@ -521,6 +526,73 @@ class Mention(object):
|
||||
def __unicode__(self):
|
||||
return '<Mention {}: offset={} length={}>'.format(self.thread_id, self.offset, self.length)
|
||||
|
||||
class QuickReply(object):
|
||||
#: 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
|
||||
is_response = None
|
||||
|
||||
def __init__(self, payload=None, data=None, is_response=False):
|
||||
"""Represents a quick reply"""
|
||||
self.payload = payload
|
||||
self.data = data
|
||||
self.is_response = is_response
|
||||
|
||||
def __repr__(self):
|
||||
return self.__unicode__()
|
||||
|
||||
def __unicode__(self):
|
||||
return '<{}: payload={!r}>'.format(self.__class__.__name__, self.payload)
|
||||
|
||||
class QuickReplyText(QuickReply):
|
||||
#: Title of the quick reply
|
||||
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__(**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__(**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__(**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__(**kwargs)
|
||||
self.image_url = image_url
|
||||
|
||||
class Poll(object):
|
||||
#: ID of the poll
|
||||
uid = None
|
||||
|
Reference in New Issue
Block a user