Skip to content

Commit

Permalink
Add forwarding attachments (#420)
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
kapi2289 authored and madsmtm committed Apr 25, 2019
1 parent 61502ed commit 70faa86
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 23 deletions.
17 changes: 17 additions & 0 deletions fbchat/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1707,6 +1707,23 @@ def sendLocalImage(
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
Expand Down
17 changes: 15 additions & 2 deletions fbchat/_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -144,12 +146,19 @@ def formatMentions(cls, text, *args, **kwargs):
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=[
Expand All @@ -160,7 +169,8 @@ def _from_graphql(cls, data):
)
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"])
Expand Down Expand Up @@ -203,13 +213,15 @@ def _from_graphql(cls, data):

@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")
Expand Down Expand Up @@ -311,6 +323,7 @@ def _from_pull(cls, data, mid=None, tags=None, author=None, timestamp=None):
)

rtn.emoji_size = EmojiSize._from_tags(tags)
rtn.forwarded = cls._get_forwarded_from_tags(tags)

return rtn

Expand Down
49 changes: 28 additions & 21 deletions fbchat/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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):
Expand Down

0 comments on commit 70faa86

Please sign in to comment.