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"])
|
plan = graphql_to_plan(j["payload"])
|
||||||
return plan
|
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
|
END FETCH METHODS
|
||||||
"""
|
"""
|
||||||
@@ -1040,6 +1064,25 @@ class Client(object):
|
|||||||
if message.sticker:
|
if message.sticker:
|
||||||
data['sticker_id'] = message.sticker.uid
|
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
|
return data
|
||||||
|
|
||||||
def _doSendRequest(self, data, get_thread_id=False):
|
def _doSendRequest(self, data, get_thread_id=False):
|
||||||
@@ -1111,6 +1154,36 @@ class Client(object):
|
|||||||
data['specific_to_list[0]'] = "fbid:{}".format(thread_id)
|
data['specific_to_list[0]'] = "fbid:{}".format(thread_id)
|
||||||
return self._doSendRequest(data)
|
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):
|
def unsend(self, mid):
|
||||||
"""
|
"""
|
||||||
Unsends a message (removes for everyone)
|
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"]
|
rtn.invited = [m.get('node').get('id') for m in guests if m.get('guest_list_state') == "INVITED"]
|
||||||
return rtn
|
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):
|
def graphql_to_message(message):
|
||||||
if message.get('message_sender') is None:
|
if message.get('message_sender') is None:
|
||||||
message['message_sender'] = {}
|
message['message_sender'] = {}
|
||||||
@@ -290,6 +308,12 @@ def graphql_to_message(message):
|
|||||||
}
|
}
|
||||||
if message.get('blob_attachments') is not None:
|
if message.get('blob_attachments') is not None:
|
||||||
rtn.attachments = [graphql_to_attachment(attachment) for attachment in message['blob_attachments']]
|
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:
|
if message.get('extensible_attachment') is not None:
|
||||||
attachment = graphql_to_extensible_attachment(message['extensible_attachment'])
|
attachment = graphql_to_extensible_attachment(message['extensible_attachment'])
|
||||||
if isinstance(attachment, UnsentMessage):
|
if isinstance(attachment, UnsentMessage):
|
||||||
|
@@ -190,10 +190,12 @@ class Message(object):
|
|||||||
sticker = None
|
sticker = None
|
||||||
#: A list of attachments
|
#: A list of attachments
|
||||||
attachments = None
|
attachments = None
|
||||||
|
#: A list of :class:`QuickReply`
|
||||||
|
quick_replies = None
|
||||||
#: Whether the message is unsent (deleted for everyone)
|
#: Whether the message is unsent (deleted for everyone)
|
||||||
unsent = None
|
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"""
|
"""Represents a Facebook message"""
|
||||||
self.text = text
|
self.text = text
|
||||||
if mentions is None:
|
if mentions is None:
|
||||||
@@ -204,6 +206,9 @@ class Message(object):
|
|||||||
if attachments is None:
|
if attachments is None:
|
||||||
attachments = []
|
attachments = []
|
||||||
self.attachments = attachments
|
self.attachments = attachments
|
||||||
|
if quick_replies is None:
|
||||||
|
quick_replies = []
|
||||||
|
self.quick_replies = quick_replies
|
||||||
self.reactions = {}
|
self.reactions = {}
|
||||||
self.read_by = []
|
self.read_by = []
|
||||||
self.deleted = False
|
self.deleted = False
|
||||||
@@ -521,6 +526,73 @@ class Mention(object):
|
|||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '<Mention {}: offset={} length={}>'.format(self.thread_id, self.offset, self.length)
|
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):
|
class Poll(object):
|
||||||
#: ID of the poll
|
#: ID of the poll
|
||||||
uid = None
|
uid = None
|
||||||
|
Reference in New Issue
Block a user