Add forwarding attachments (#420)

- Add ability to forward attachments and `Message.forwarded` attribute
- Improve error handling for a lot of client methods, including, but not limited to:
    - `fetchAllUsers`
    - `searchForMessageIDs`
    - `search`
    - `fetchThreadInfo` and siblings
    - `fetchUnread`
    - `fetchUnseen`
    - `fetchPollOptions`
    - `fetchPlanInfo`
    - `send` and siblings
    - File uploads
This commit is contained in:
Kacper Ziubryniewicz
2019-04-25 22:03:03 +02:00
committed by Mads Marquart
parent 61502ed32a
commit 70faa86e34
3 changed files with 60 additions and 23 deletions

View File

@@ -1707,6 +1707,23 @@ class Client(object):
thread_type=thread_type,
)
def forwardAttachment(self, attachment_id, thread_id=None):
"""
Forwards an attachment
:param attachment_id: Attachment ID to forward
:param thread_id: User/Group ID to send to. See :ref:`intro_threads`
:raises: FBchatException if request failed
"""
thread_id, thread_type = self._getThread(thread_id, None)
data = {
"attachment_id": attachment_id,
"recipient_map[{}]".format(generateOfflineThreadingID()): thread_id,
}
j = self._post(
self.req_url.FORWARD_ATTACHMENT, data, fix_request=True, as_json=True
)
def createGroup(self, message, user_ids):
"""
Creates a group with the given ids

View File

@@ -90,6 +90,8 @@ class Message(object):
reply_to_id = attr.ib(None)
#: Replied message
replied_to = attr.ib(None, init=False)
#: Whether the message was forwarded
forwarded = attr.ib(False, init=False)
@classmethod
def formatMentions(cls, text, *args, **kwargs):
@@ -144,12 +146,19 @@ class Message(object):
message = cls(text=result, mentions=mentions)
return message
@staticmethod
def _get_forwarded_from_tags(tags):
if tags is None:
return False
return any(map(lambda tag: "forward" in tag or "copy" in tag, tags))
@classmethod
def _from_graphql(cls, data):
if data.get("message_sender") is None:
data["message_sender"] = {}
if data.get("message") is None:
data["message"] = {}
tags = data.get("tags_list")
rtn = cls(
text=data["message"].get("text"),
mentions=[
@@ -160,7 +169,8 @@ class Message(object):
)
for m in data["message"].get("ranges") or ()
],
emoji_size=EmojiSize._from_tags(data.get("tags_list")),
emoji_size=EmojiSize._from_tags(tags),
forwarded=cls._get_forwarded_from_tags(tags),
sticker=_sticker.Sticker._from_graphql(data.get("sticker")),
)
rtn.uid = str(data["message_id"])
@@ -203,13 +213,15 @@ class Message(object):
@classmethod
def _from_reply(cls, data):
tags = data["messageMetadata"].get("tags")
rtn = cls(
text=data.get("body"),
mentions=[
Mention(m.get("i"), offset=m.get("o"), length=m.get("l"))
for m in json.loads(data.get("data", {}).get("prng", "[]"))
],
emoji_size=EmojiSize._from_tags(data["messageMetadata"].get("tags")),
emoji_size=EmojiSize._from_tags(tags),
forwarded=cls._get_forwarded_from_tags(tags),
)
metadata = data.get("messageMetadata", {})
rtn.uid = metadata.get("messageId")
@@ -311,6 +323,7 @@ class Message(object):
)
rtn.emoji_size = EmojiSize._from_tags(tags)
rtn.forwarded = cls._get_forwarded_from_tags(tags)
return rtn

View File

@@ -114,6 +114,7 @@ class ReqUrl(object):
SEARCH_MESSAGES = "https://www.facebook.com/ajax/mercury/search_snippets.php?dpr=1"
MARK_SPAM = "https://www.facebook.com/ajax/mercury/mark_spam.php?dpr=1"
UNSEND = "https://www.facebook.com/messaging/unsend_message/?dpr=1"
FORWARD_ATTACHMENT = "https://www.facebook.com/mercury/attachments/forward/"
pull_channel = 0
@@ -192,29 +193,35 @@ def generateOfflineThreadingID():
def check_json(j):
if j.get("error") is None:
return
if "errorDescription" in j:
# 'errorDescription' is in the users own language!
if j.get("payload") and j["payload"].get("error"):
raise FBchatFacebookError(
"Error #{} when sending request: {}".format(
j["error"], j["errorDescription"]
),
fb_error_code=j["error"],
fb_error_message=j["errorDescription"],
)
elif "debug_info" in j["error"] and "code" in j["error"]:
raise FBchatFacebookError(
"Error #{} when sending request: {}".format(
j["error"]["code"], repr(j["error"]["debug_info"])
),
fb_error_code=j["error"]["code"],
fb_error_message=j["error"]["debug_info"],
)
else:
raise FBchatFacebookError(
"Error {} when sending request".format(j["error"]), fb_error_code=j["error"]
"Error when sending request: {}".format(j["payload"]["error"]),
fb_error_code=None,
fb_error_message=j["payload"]["error"],
)
elif j.get("error"):
if "errorDescription" in j:
# 'errorDescription' is in the users own language!
raise FBchatFacebookError(
"Error #{} when sending request: {}".format(
j["error"], j["errorDescription"]
),
fb_error_code=j["error"],
fb_error_message=j["errorDescription"],
)
elif "debug_info" in j["error"] and "code" in j["error"]:
raise FBchatFacebookError(
"Error #{} when sending request: {}".format(
j["error"]["code"], repr(j["error"]["debug_info"])
),
fb_error_code=j["error"]["code"],
fb_error_message=j["error"]["debug_info"],
)
else:
raise FBchatFacebookError(
"Error {} when sending request".format(j["error"]),
fb_error_code=j["error"],
)
def check_request(r, as_json=True):