Merge pull request #432 from carpedm20/undocumented-breaking-changes

Undocumented breaking changes
This commit is contained in:
Mads Marquart
2019-06-23 17:51:37 +02:00
committed by GitHub
5 changed files with 68 additions and 117 deletions

View File

@@ -31,14 +31,3 @@ A good tip is to write ``from fbchat.models import *`` at the start of your sour
.. automodule:: fbchat.models .. automodule:: fbchat.models
:members: :members:
:undoc-members: :undoc-members:
.. _api_utils:
Utils
-----
These functions and values are used internally by fbchat, and are subject to change. Do **NOT** rely on these to be backwards compatible!
.. automodule:: fbchat.utils
:members:

View File

@@ -7,11 +7,10 @@
from __future__ import unicode_literals from __future__ import unicode_literals
# These imports are far too general, but they're needed for backwards compatbility. # These imports are far too general, but they're needed for backwards compatbility.
from .utils import *
from .models import * from .models import *
from ._graphql import graphql_queries_to_json, graphql_response_to_json, GraphQL
from ._client import Client from ._client import Client
from ._util import log # TODO: Remove this (from examples too)
__title__ = "fbchat" __title__ = "fbchat"
__version__ = "1.6.5" __version__ = "1.6.5"

View File

@@ -59,7 +59,7 @@ class Client(object):
:param email: Facebook `email`, `id` or `phone number` :param email: Facebook `email`, `id` or `phone number`
:param password: Facebook account password :param password: Facebook account password
:param user_agent: Custom user agent to use when sending requests. If `None`, user agent will be chosen from a premade list (see :any:`utils.USER_AGENTS`) :param user_agent: Custom user agent to use when sending requests. If `None`, user agent will be chosen from a premade list
:param max_tries: Maximum number of times to try logging in :param max_tries: Maximum number of times to try logging in
:param session_cookies: Cookies from a previous session (Will default to login if these are invalid) :param session_cookies: Cookies from a previous session (Will default to login if these are invalid)
:param logging_level: Configures the `logging level <https://docs.python.org/3/library/logging.html#logging-levels>`_. Defaults to `INFO` :param logging_level: Configures the `logging level <https://docs.python.org/3/library/logging.html#logging-levels>`_. Defaults to `INFO`
@@ -76,7 +76,7 @@ class Client(object):
self._payload_default = OrderedDict() self._payload_default = OrderedDict()
self._default_thread_id = None self._default_thread_id = None
self._default_thread_type = None self._default_thread_type = None
self.req_url = ReqUrl() self._req_url = ReqUrl()
self._markAlive = True self._markAlive = True
self._buddylist = dict() self._buddylist = dict()
@@ -85,8 +85,8 @@ class Client(object):
self._header = { self._header = {
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": "application/x-www-form-urlencoded",
"Referer": self.req_url.BASE, "Referer": self._req_url.BASE,
"Origin": self.req_url.BASE, "Origin": self._req_url.BASE,
"User-Agent": user_agent, "User-Agent": user_agent,
"Connection": "keep-alive", "Connection": "keep-alive",
} }
@@ -276,7 +276,7 @@ class Client(object):
"queries": graphql_queries_to_json(*queries), "queries": graphql_queries_to_json(*queries),
} }
return tuple( return tuple(
self._post(self.req_url.GRAPHQL, data, fix_request=True, as_graphql=True) self._post(self._req_url.GRAPHQL, data, fix_request=True, as_graphql=True)
) )
def graphql_request(self, query): def graphql_request(self, query):
@@ -310,7 +310,7 @@ class Client(object):
raise FBchatException("Could not find c_user cookie") raise FBchatException("Could not find c_user cookie")
self._uid = str(self._uid) self._uid = str(self._uid)
r = self._get(self.req_url.BASE) r = self._get(self._req_url.BASE)
soup = bs(r.text, "html.parser") soup = bs(r.text, "html.parser")
fb_dtsg_element = soup.find("input", {"name": "fb_dtsg"}) fb_dtsg_element = soup.find("input", {"name": "fb_dtsg"})
@@ -337,7 +337,7 @@ class Client(object):
self._payload_default["fb_dtsg"] = fb_dtsg self._payload_default["fb_dtsg"] = fb_dtsg
def _login(self, email, password): def _login(self, email, password):
soup = bs(self._get(self.req_url.MOBILE).text, "html.parser") soup = bs(self._get(self._req_url.MOBILE).text, "html.parser")
data = dict( data = dict(
(elem["name"], elem["value"]) (elem["name"], elem["value"])
for elem in soup.findAll("input") for elem in soup.findAll("input")
@@ -347,7 +347,7 @@ class Client(object):
data["pass"] = password data["pass"] = password
data["login"] = "Log In" data["login"] = "Log In"
r = self._cleanPost(self.req_url.LOGIN, data) r = self._cleanPost(self._req_url.LOGIN, data)
# Usually, 'Checkpoint' will refer to 2FA # Usually, 'Checkpoint' will refer to 2FA
if "checkpoint" in r.url and ('id="approvals_code"' in r.text.lower()): if "checkpoint" in r.url and ('id="approvals_code"' in r.text.lower()):
@@ -355,7 +355,7 @@ class Client(object):
# Sometimes Facebook tries to show the user a "Save Device" dialog # Sometimes Facebook tries to show the user a "Save Device" dialog
if "save-device" in r.url: if "save-device" in r.url:
r = self._cleanGet(self.req_url.SAVE_DEVICE) r = self._cleanGet(self._req_url.SAVE_DEVICE)
if "home" in r.url: if "home" in r.url:
self._postLogin() self._postLogin()
@@ -376,7 +376,7 @@ class Client(object):
data["codes_submitted"] = 0 data["codes_submitted"] = 0
log.info("Submitting 2FA code.") log.info("Submitting 2FA code.")
r = self._cleanPost(self.req_url.CHECKPOINT, data) r = self._cleanPost(self._req_url.CHECKPOINT, data)
if "home" in r.url: if "home" in r.url:
return r return r
@@ -390,7 +390,7 @@ class Client(object):
log.info( log.info(
"Saving browser." "Saving browser."
) # At this stage, we have dtsg, nh, name_action_selected, submit[Continue] ) # At this stage, we have dtsg, nh, name_action_selected, submit[Continue]
r = self._cleanPost(self.req_url.CHECKPOINT, data) r = self._cleanPost(self._req_url.CHECKPOINT, data)
if "home" in r.url: if "home" in r.url:
return r return r
@@ -399,7 +399,7 @@ class Client(object):
log.info( log.info(
"Starting Facebook checkup flow." "Starting Facebook checkup flow."
) # At this stage, we have dtsg, nh, submit[Continue] ) # At this stage, we have dtsg, nh, submit[Continue]
r = self._cleanPost(self.req_url.CHECKPOINT, data) r = self._cleanPost(self._req_url.CHECKPOINT, data)
if "home" in r.url: if "home" in r.url:
return r return r
@@ -409,7 +409,7 @@ class Client(object):
log.info( log.info(
"Verifying login attempt." "Verifying login attempt."
) # At this stage, we have dtsg, nh, submit[This was me] ) # At this stage, we have dtsg, nh, submit[This was me]
r = self._cleanPost(self.req_url.CHECKPOINT, data) r = self._cleanPost(self._req_url.CHECKPOINT, data)
if "home" in r.url: if "home" in r.url:
return r return r
@@ -420,7 +420,7 @@ class Client(object):
log.info( log.info(
"Saving device again." "Saving device again."
) # At this stage, we have dtsg, nh, submit[Continue], name_action_selected ) # At this stage, we have dtsg, nh, submit[Continue], name_action_selected
r = self._cleanPost(self.req_url.CHECKPOINT, data) r = self._cleanPost(self._req_url.CHECKPOINT, data)
return r return r
def isLoggedIn(self): def isLoggedIn(self):
@@ -431,7 +431,7 @@ class Client(object):
:rtype: bool :rtype: bool
""" """
# Send a request to the login url, to see if we're directed to the home page # Send a request to the login url, to see if we're directed to the home page
r = self._cleanGet(self.req_url.LOGIN, allow_redirects=False) r = self._cleanGet(self._req_url.LOGIN, allow_redirects=False)
return "Location" in r.headers and "home" in r.headers["Location"] return "Location" in r.headers and "home" in r.headers["Location"]
def getSession(self): def getSession(self):
@@ -512,12 +512,12 @@ class Client(object):
:rtype: bool :rtype: bool
""" """
if not hasattr(self, "_fb_h"): if not hasattr(self, "_fb_h"):
h_r = self._post(self.req_url.MODERN_SETTINGS_MENU, {"pmid": "4"}) h_r = self._post(self._req_url.MODERN_SETTINGS_MENU, {"pmid": "4"})
self._fb_h = re.search(r'name=\\"h\\" value=\\"(.*?)\\"', h_r.text).group(1) self._fb_h = re.search(r'name=\\"h\\" value=\\"(.*?)\\"', h_r.text).group(1)
data = {"ref": "mb", "h": self._fb_h} data = {"ref": "mb", "h": self._fb_h}
r = self._get(self.req_url.LOGOUT, data) r = self._get(self._req_url.LOGOUT, data)
self._resetValues() self._resetValues()
@@ -663,7 +663,7 @@ class Client(object):
""" """
data = {"viewer": self._uid} data = {"viewer": self._uid}
j = self._post( j = self._post(
self.req_url.ALL_USERS, query=data, fix_request=True, as_json=True self._req_url.ALL_USERS, query=data, fix_request=True, as_json=True
) )
if j.get("payload") is None: if j.get("payload") is None:
raise FBchatException("Missing payload while fetching users: {}".format(j)) raise FBchatException("Missing payload while fetching users: {}".format(j))
@@ -777,7 +777,7 @@ class Client(object):
"thread_fbid": thread_id, "thread_fbid": thread_id,
} }
j = self._post( j = self._post(
self.req_url.SEARCH_MESSAGES, data, fix_request=True, as_json=True self._req_url.SEARCH_MESSAGES, data, fix_request=True, as_json=True
) )
result = j["payload"]["search_snippets"][query] result = j["payload"]["search_snippets"][query]
@@ -824,7 +824,7 @@ class Client(object):
""" """
data = {"query": query, "snippetLimit": thread_limit} data = {"query": query, "snippetLimit": thread_limit}
j = self._post( j = self._post(
self.req_url.SEARCH_MESSAGES, data, fix_request=True, as_json=True self._req_url.SEARCH_MESSAGES, data, fix_request=True, as_json=True
) )
result = j["payload"]["search_snippets"][query] result = j["payload"]["search_snippets"][query]
@@ -843,7 +843,7 @@ class Client(object):
def _fetchInfo(self, *ids): def _fetchInfo(self, *ids):
data = {"ids[{}]".format(i): _id for i, _id in enumerate(ids)} data = {"ids[{}]".format(i): _id for i, _id in enumerate(ids)}
j = self._post(self.req_url.INFO, data, fix_request=True, as_json=True) j = self._post(self._req_url.INFO, data, fix_request=True, as_json=True)
if j.get("payload") is None or j["payload"].get("profiles") is None: if j.get("payload") is None or j["payload"].get("profiles") is None:
raise FBchatException("No users/pages returned: {}".format(j)) raise FBchatException("No users/pages returned: {}".format(j))
@@ -1114,7 +1114,7 @@ class Client(object):
# 'last_action_timestamp': 0 # 'last_action_timestamp': 0
} }
j = self._post( j = self._post(
self.req_url.UNREAD_THREADS, form, fix_request=True, as_json=True self._req_url.UNREAD_THREADS, form, fix_request=True, as_json=True
) )
payload = j["payload"]["unread_thread_fbids"][0] payload = j["payload"]["unread_thread_fbids"][0]
@@ -1129,7 +1129,7 @@ class Client(object):
:raises: FBchatException if request failed :raises: FBchatException if request failed
""" """
j = self._post( j = self._post(
self.req_url.UNSEEN_THREADS, None, fix_request=True, as_json=True self._req_url.UNSEEN_THREADS, None, fix_request=True, as_json=True
) )
payload = j["payload"]["unseen_thread_fbids"][0] payload = j["payload"]["unseen_thread_fbids"][0]
@@ -1179,7 +1179,7 @@ class Client(object):
""" """
data = {"question_id": poll_id} data = {"question_id": poll_id}
j = self._post( j = self._post(
self.req_url.GET_POLL_OPTIONS, data, fix_request=True, as_json=True self._req_url.GET_POLL_OPTIONS, data, fix_request=True, as_json=True
) )
return [PollOption._from_graphql(m) for m in j["payload"]] return [PollOption._from_graphql(m) for m in j["payload"]]
@@ -1193,7 +1193,7 @@ class Client(object):
:raises: FBchatException if request failed :raises: FBchatException if request failed
""" """
data = {"event_reminder_id": plan_id} data = {"event_reminder_id": plan_id}
j = self._post(self.req_url.PLAN_INFO, data, fix_request=True, as_json=True) j = self._post(self._req_url.PLAN_INFO, data, fix_request=True, as_json=True)
return Plan._from_fetch(j["payload"]) return Plan._from_fetch(j["payload"])
def _getPrivateData(self): def _getPrivateData(self):
@@ -1318,7 +1318,7 @@ class Client(object):
def _doSendRequest(self, data, get_thread_id=False): def _doSendRequest(self, data, get_thread_id=False):
"""Sends the data to `SendURL`, and returns the message ID or None on failure""" """Sends the data to `SendURL`, and returns the message ID or None on failure"""
j = self._post(self.req_url.SEND, data, fix_request=True, as_json=True) j = self._post(self._req_url.SEND, data, fix_request=True, as_json=True)
# update JS token if received in response # update JS token if received in response
fb_dtsg = get_jsmods_require(j, 2) fb_dtsg = get_jsmods_require(j, 2)
@@ -1453,7 +1453,7 @@ class Client(object):
:param mid: :ref:`Message ID <intro_message_ids>` of the message to unsend :param mid: :ref:`Message ID <intro_message_ids>` of the message to unsend
""" """
data = {"message_id": mid} data = {"message_id": mid}
r = self._post(self.req_url.UNSEND, data) r = self._post(self._req_url.UNSEND, data)
r.raise_for_status() r.raise_for_status()
def _sendLocation( def _sendLocation(
@@ -1529,7 +1529,7 @@ class Client(object):
data = {"voice_clip": voice_clip} data = {"voice_clip": voice_clip}
j = self._postFile( j = self._postFile(
self.req_url.UPLOAD, self._req_url.UPLOAD,
files=file_dict, files=file_dict,
query=data, query=data,
fix_request=True, fix_request=True,
@@ -1713,7 +1713,7 @@ class Client(object):
"recipient_map[{}]".format(generateOfflineThreadingID()): thread_id, "recipient_map[{}]".format(generateOfflineThreadingID()): thread_id,
} }
j = self._post( j = self._post(
self.req_url.FORWARD_ATTACHMENT, data, fix_request=True, as_json=True self._req_url.FORWARD_ATTACHMENT, data, fix_request=True, as_json=True
) )
def createGroup(self, message, user_ids): def createGroup(self, message, user_ids):
@@ -1780,7 +1780,7 @@ class Client(object):
thread_id, thread_type = self._getThread(thread_id, None) thread_id, thread_type = self._getThread(thread_id, None)
data = {"uid": user_id, "tid": thread_id} data = {"uid": user_id, "tid": thread_id}
j = self._post(self.req_url.REMOVE_USER, data, fix_request=True, as_json=True) j = self._post(self._req_url.REMOVE_USER, data, fix_request=True, as_json=True)
def _adminStatus(self, admin_ids, admin, thread_id=None): def _adminStatus(self, admin_ids, admin, thread_id=None):
thread_id, thread_type = self._getThread(thread_id, None) thread_id, thread_type = self._getThread(thread_id, None)
@@ -1792,7 +1792,7 @@ class Client(object):
for i, admin_id in enumerate(admin_ids): for i, admin_id in enumerate(admin_ids):
data["admin_ids[{}]".format(i)] = str(admin_id) data["admin_ids[{}]".format(i)] = str(admin_id)
j = self._post(self.req_url.SAVE_ADMINS, data, fix_request=True, as_json=True) j = self._post(self._req_url.SAVE_ADMINS, data, fix_request=True, as_json=True)
def addGroupAdmins(self, admin_ids, thread_id=None): def addGroupAdmins(self, admin_ids, thread_id=None):
""" """
@@ -1825,7 +1825,9 @@ class Client(object):
thread_id, thread_type = self._getThread(thread_id, None) thread_id, thread_type = self._getThread(thread_id, None)
data = {"set_mode": int(require_admin_approval), "thread_fbid": thread_id} data = {"set_mode": int(require_admin_approval), "thread_fbid": thread_id}
j = self._post(self.req_url.APPROVAL_MODE, data, fix_request=True, as_json=True) j = self._post(
self._req_url.APPROVAL_MODE, data, fix_request=True, as_json=True
)
def _usersApproval(self, user_ids, approve, thread_id=None): def _usersApproval(self, user_ids, approve, thread_id=None):
thread_id, thread_type = self._getThread(thread_id, None) thread_id, thread_type = self._getThread(thread_id, None)
@@ -1876,7 +1878,7 @@ class Client(object):
data = {"thread_image_id": image_id, "thread_id": thread_id} data = {"thread_image_id": image_id, "thread_id": thread_id}
j = self._post(self.req_url.THREAD_IMAGE, data, fix_request=True, as_json=True) j = self._post(self._req_url.THREAD_IMAGE, data, fix_request=True, as_json=True)
return image_id return image_id
def changeGroupImageRemote(self, image_url, thread_id=None): def changeGroupImageRemote(self, image_url, thread_id=None):
@@ -1923,7 +1925,7 @@ class Client(object):
) )
data = {"thread_name": title, "thread_id": thread_id} data = {"thread_name": title, "thread_id": thread_id}
j = self._post(self.req_url.THREAD_NAME, data, fix_request=True, as_json=True) j = self._post(self._req_url.THREAD_NAME, data, fix_request=True, as_json=True)
def changeNickname( def changeNickname(
self, nickname, user_id, thread_id=None, thread_type=ThreadType.USER self, nickname, user_id, thread_id=None, thread_type=ThreadType.USER
@@ -1946,7 +1948,7 @@ class Client(object):
"thread_or_other_fbid": thread_id, "thread_or_other_fbid": thread_id,
} }
j = self._post( j = self._post(
self.req_url.THREAD_NICKNAME, data, fix_request=True, as_json=True self._req_url.THREAD_NICKNAME, data, fix_request=True, as_json=True
) )
def changeThreadColor(self, color, thread_id=None): def changeThreadColor(self, color, thread_id=None):
@@ -1964,7 +1966,7 @@ class Client(object):
"color_choice": color.value if color != ThreadColor.MESSENGER_BLUE else "", "color_choice": color.value if color != ThreadColor.MESSENGER_BLUE else "",
"thread_or_other_fbid": thread_id, "thread_or_other_fbid": thread_id,
} }
j = self._post(self.req_url.THREAD_COLOR, data, fix_request=True, as_json=True) j = self._post(self._req_url.THREAD_COLOR, data, fix_request=True, as_json=True)
def changeThreadEmoji(self, emoji, thread_id=None): def changeThreadEmoji(self, emoji, thread_id=None):
""" """
@@ -1979,7 +1981,7 @@ class Client(object):
thread_id, thread_type = self._getThread(thread_id, None) thread_id, thread_type = self._getThread(thread_id, None)
data = {"emoji_choice": emoji, "thread_or_other_fbid": thread_id} data = {"emoji_choice": emoji, "thread_or_other_fbid": thread_id}
j = self._post(self.req_url.THREAD_EMOJI, data, fix_request=True, as_json=True) j = self._post(self._req_url.THREAD_EMOJI, data, fix_request=True, as_json=True)
def reactToMessage(self, message_id, reaction): def reactToMessage(self, message_id, reaction):
""" """
@@ -1998,7 +2000,7 @@ class Client(object):
"reaction": reaction.value if reaction else None, "reaction": reaction.value if reaction else None,
} }
data = {"doc_id": 1491398900900362, "variables": json.dumps({"data": data})} data = {"doc_id": 1491398900900362, "variables": json.dumps({"data": data})}
self._post(self.req_url.MESSAGE_REACTION, data, fix_request=True, as_json=True) self._post(self._req_url.MESSAGE_REACTION, data, fix_request=True, as_json=True)
def createPlan(self, plan, thread_id=None): def createPlan(self, plan, thread_id=None):
""" """
@@ -2020,7 +2022,7 @@ class Client(object):
"location_name": plan.location or "", "location_name": plan.location or "",
"acontext": ACONTEXT, "acontext": ACONTEXT,
} }
j = self._post(self.req_url.PLAN_CREATE, data, fix_request=True, as_json=True) j = self._post(self._req_url.PLAN_CREATE, data, fix_request=True, as_json=True)
def editPlan(self, plan, new_plan): def editPlan(self, plan, new_plan):
""" """
@@ -2040,7 +2042,7 @@ class Client(object):
"title": new_plan.title, "title": new_plan.title,
"acontext": ACONTEXT, "acontext": ACONTEXT,
} }
j = self._post(self.req_url.PLAN_CHANGE, data, fix_request=True, as_json=True) j = self._post(self._req_url.PLAN_CHANGE, data, fix_request=True, as_json=True)
def deletePlan(self, plan): def deletePlan(self, plan):
""" """
@@ -2050,7 +2052,7 @@ class Client(object):
:raises: FBchatException if request failed :raises: FBchatException if request failed
""" """
data = {"event_reminder_id": plan.uid, "delete": "true", "acontext": ACONTEXT} data = {"event_reminder_id": plan.uid, "delete": "true", "acontext": ACONTEXT}
j = self._post(self.req_url.PLAN_CHANGE, data, fix_request=True, as_json=True) j = self._post(self._req_url.PLAN_CHANGE, data, fix_request=True, as_json=True)
def changePlanParticipation(self, plan, take_part=True): def changePlanParticipation(self, plan, take_part=True):
""" """
@@ -2066,7 +2068,7 @@ class Client(object):
"acontext": ACONTEXT, "acontext": ACONTEXT,
} }
j = self._post( j = self._post(
self.req_url.PLAN_PARTICIPATION, data, fix_request=True, as_json=True self._req_url.PLAN_PARTICIPATION, data, fix_request=True, as_json=True
) )
def eventReminder(self, thread_id, time, title, location="", location_id=""): def eventReminder(self, thread_id, time, title, location="", location_id=""):
@@ -2100,7 +2102,7 @@ class Client(object):
data["option_text_array[{}]".format(i)] = option.text data["option_text_array[{}]".format(i)] = option.text
data["option_is_selected_array[{}]".format(i)] = str(int(option.vote)) data["option_is_selected_array[{}]".format(i)] = str(int(option.vote))
j = self._post(self.req_url.CREATE_POLL, data, fix_request=True, as_json=True) j = self._post(self._req_url.CREATE_POLL, data, fix_request=True, as_json=True)
def updatePollVote(self, poll_id, option_ids=[], new_options=[]): def updatePollVote(self, poll_id, option_ids=[], new_options=[]):
""" """
@@ -2122,7 +2124,7 @@ class Client(object):
for i, option_text in enumerate(new_options): for i, option_text in enumerate(new_options):
data["new_options[{}]".format(i)] = option_text data["new_options[{}]".format(i)] = option_text
j = self._post(self.req_url.UPDATE_VOTE, data, fix_request=True, as_json=True) j = self._post(self._req_url.UPDATE_VOTE, data, fix_request=True, as_json=True)
def setTypingStatus(self, status, thread_id=None, thread_type=None): def setTypingStatus(self, status, thread_id=None, thread_type=None):
""" """
@@ -2143,7 +2145,7 @@ class Client(object):
"to": thread_id if thread_type == ThreadType.USER else "", "to": thread_id if thread_type == ThreadType.USER else "",
"source": "mercury-chat", "source": "mercury-chat",
} }
j = self._post(self.req_url.TYPING, data, fix_request=True, as_json=True) j = self._post(self._req_url.TYPING, data, fix_request=True, as_json=True)
""" """
END SEND METHODS END SEND METHODS
@@ -2163,7 +2165,7 @@ class Client(object):
"thread_ids[%s][0]" % thread_id: message_id, "thread_ids[%s][0]" % thread_id: message_id,
} }
r = self._post(self.req_url.DELIVERED, data) r = self._post(self._req_url.DELIVERED, data)
return r.ok return r.ok
def _readStatus(self, read, thread_ids): def _readStatus(self, read, thread_ids):
@@ -2174,7 +2176,7 @@ class Client(object):
for thread_id in thread_ids: for thread_id in thread_ids:
data["ids[{}]".format(thread_id)] = "true" if read else "false" data["ids[{}]".format(thread_id)] = "true" if read else "false"
r = self._post(self.req_url.READ_STATUS, data) r = self._post(self._req_url.READ_STATUS, data)
return r.ok return r.ok
def markAsRead(self, thread_ids=None): def markAsRead(self, thread_ids=None):
@@ -2204,7 +2206,7 @@ class Client(object):
.. todo:: .. todo::
Documenting this Documenting this
""" """
r = self._post(self.req_url.MARK_SEEN, {"seen_timestamp": now()}) r = self._post(self._req_url.MARK_SEEN, {"seen_timestamp": now()})
return r.ok return r.ok
def friendConnect(self, friend_id): def friendConnect(self, friend_id):
@@ -2214,7 +2216,7 @@ class Client(object):
""" """
data = {"to_friend": friend_id, "action": "confirm"} data = {"to_friend": friend_id, "action": "confirm"}
r = self._post(self.req_url.CONNECT, data) r = self._post(self._req_url.CONNECT, data)
return r.ok return r.ok
def removeFriend(self, friend_id=None): def removeFriend(self, friend_id=None):
@@ -2225,7 +2227,7 @@ class Client(object):
:return: Returns error if the removing was unsuccessful, returns True when successful. :return: Returns error if the removing was unsuccessful, returns True when successful.
""" """
payload = {"friend_id": friend_id, "unref": "none", "confirm": "Confirm"} payload = {"friend_id": friend_id, "unref": "none", "confirm": "Confirm"}
r = self._post(self.req_url.REMOVE_FRIEND, payload) r = self._post(self._req_url.REMOVE_FRIEND, payload)
query = parse_qs(urlparse(r.url).query) query = parse_qs(urlparse(r.url).query)
if "err" not in query: if "err" not in query:
log.debug("Remove was successful!") log.debug("Remove was successful!")
@@ -2243,7 +2245,7 @@ class Client(object):
:raises: FBchatException if request failed :raises: FBchatException if request failed
""" """
data = {"fbid": user_id} data = {"fbid": user_id}
r = self._post(self.req_url.BLOCK_USER, data) r = self._post(self._req_url.BLOCK_USER, data)
return r.ok return r.ok
def unblockUser(self, user_id): def unblockUser(self, user_id):
@@ -2255,7 +2257,7 @@ class Client(object):
:raises: FBchatException if request failed :raises: FBchatException if request failed
""" """
data = {"fbid": user_id} data = {"fbid": user_id}
r = self._post(self.req_url.UNBLOCK_USER, data) r = self._post(self._req_url.UNBLOCK_USER, data)
return r.ok return r.ok
def moveThreads(self, location, thread_ids): def moveThreads(self, location, thread_ids):
@@ -2278,14 +2280,14 @@ class Client(object):
for thread_id in thread_ids: for thread_id in thread_ids:
data_archive["ids[{}]".format(thread_id)] = "true" data_archive["ids[{}]".format(thread_id)] = "true"
data_unpin["ids[{}]".format(thread_id)] = "false" data_unpin["ids[{}]".format(thread_id)] = "false"
r_archive = self._post(self.req_url.ARCHIVED_STATUS, data_archive) r_archive = self._post(self._req_url.ARCHIVED_STATUS, data_archive)
r_unpin = self._post(self.req_url.PINNED_STATUS, data_unpin) r_unpin = self._post(self._req_url.PINNED_STATUS, data_unpin)
return r_archive.ok and r_unpin.ok return r_archive.ok and r_unpin.ok
else: else:
data = dict() data = dict()
for i, thread_id in enumerate(thread_ids): for i, thread_id in enumerate(thread_ids):
data["{}[{}]".format(location.name.lower(), i)] = thread_id data["{}[{}]".format(location.name.lower(), i)] = thread_id
r = self._post(self.req_url.MOVE_THREAD, data) r = self._post(self._req_url.MOVE_THREAD, data)
return r.ok return r.ok
def deleteThreads(self, thread_ids): def deleteThreads(self, thread_ids):
@@ -2303,8 +2305,8 @@ class Client(object):
for i, thread_id in enumerate(thread_ids): for i, thread_id in enumerate(thread_ids):
data_unpin["ids[{}]".format(thread_id)] = "false" data_unpin["ids[{}]".format(thread_id)] = "false"
data_delete["ids[{}]".format(i)] = thread_id data_delete["ids[{}]".format(i)] = thread_id
r_unpin = self._post(self.req_url.PINNED_STATUS, data_unpin) r_unpin = self._post(self._req_url.PINNED_STATUS, data_unpin)
r_delete = self._post(self.req_url.DELETE_THREAD, data_delete) r_delete = self._post(self._req_url.DELETE_THREAD, data_delete)
return r_unpin.ok and r_delete.ok return r_unpin.ok and r_delete.ok
def markAsSpam(self, thread_id=None): def markAsSpam(self, thread_id=None):
@@ -2316,7 +2318,7 @@ class Client(object):
:raises: FBchatException if request failed :raises: FBchatException if request failed
""" """
thread_id, thread_type = self._getThread(thread_id, None) thread_id, thread_type = self._getThread(thread_id, None)
r = self._post(self.req_url.MARK_SPAM, {"id": thread_id}) r = self._post(self._req_url.MARK_SPAM, {"id": thread_id})
return r.ok return r.ok
def deleteMessages(self, message_ids): def deleteMessages(self, message_ids):
@@ -2331,7 +2333,7 @@ class Client(object):
data = dict() data = dict()
for i, message_id in enumerate(message_ids): for i, message_id in enumerate(message_ids):
data["message_ids[{}]".format(i)] = message_id data["message_ids[{}]".format(i)] = message_id
r = self._post(self.req_url.DELETE_MESSAGES, data) r = self._post(self._req_url.DELETE_MESSAGES, data)
return r.ok return r.ok
def muteThread(self, mute_time=-1, thread_id=None): def muteThread(self, mute_time=-1, thread_id=None):
@@ -2343,7 +2345,7 @@ class Client(object):
""" """
thread_id, thread_type = self._getThread(thread_id, None) thread_id, thread_type = self._getThread(thread_id, None)
data = {"mute_settings": str(mute_time), "thread_fbid": thread_id} data = {"mute_settings": str(mute_time), "thread_fbid": thread_id}
content = self._post(self.req_url.MUTE_THREAD, data, fix_request=True) content = self._post(self._req_url.MUTE_THREAD, data, fix_request=True)
def unmuteThread(self, thread_id=None): def unmuteThread(self, thread_id=None):
""" """
@@ -2362,7 +2364,7 @@ class Client(object):
""" """
thread_id, thread_type = self._getThread(thread_id, None) thread_id, thread_type = self._getThread(thread_id, None)
data = {"reactions_mute_mode": int(mute), "thread_fbid": thread_id} data = {"reactions_mute_mode": int(mute), "thread_fbid": thread_id}
r = self._post(self.req_url.MUTE_REACTIONS, data, fix_request=True) r = self._post(self._req_url.MUTE_REACTIONS, data, fix_request=True)
def unmuteThreadReactions(self, thread_id=None): def unmuteThreadReactions(self, thread_id=None):
""" """
@@ -2381,7 +2383,7 @@ class Client(object):
""" """
thread_id, thread_type = self._getThread(thread_id, None) thread_id, thread_type = self._getThread(thread_id, None)
data = {"mentions_mute_mode": int(mute), "thread_fbid": thread_id} data = {"mentions_mute_mode": int(mute), "thread_fbid": thread_id}
r = self._post(self.req_url.MUTE_MENTIONS, data, fix_request=True) r = self._post(self._req_url.MUTE_MENTIONS, data, fix_request=True)
def unmuteThreadMentions(self, thread_id=None): def unmuteThreadMentions(self, thread_id=None):
""" """
@@ -2407,7 +2409,7 @@ class Client(object):
"viewer_uid": self._uid, "viewer_uid": self._uid,
"state": "active", "state": "active",
} }
self._get(self.req_url.PING, data, fix_request=True, as_json=False) self._get(self._req_url.PING, data, fix_request=True, as_json=False)
def _pullMessage(self): def _pullMessage(self):
"""Call pull api with seq value to get message data.""" """Call pull api with seq value to get message data."""
@@ -2418,7 +2420,7 @@ class Client(object):
"clientid": self._client_id, "clientid": self._client_id,
"state": "active" if self._markAlive else "offline", "state": "active" if self._markAlive else "offline",
} }
return self._get(self.req_url.STICKY, data, fix_request=True, as_json=True) return self._get(self._req_url.STICKY, data, fix_request=True, as_json=True)
def _parseDelta(self, m): def _parseDelta(self, m):
def getThreadIdAndThreadType(msg_metadata): def getThreadIdAndThreadType(msg_metadata):
@@ -3110,7 +3112,7 @@ class Client(object):
except FBchatFacebookError as e: except FBchatFacebookError as e:
# Fix 502 and 503 pull errors # Fix 502 and 503 pull errors
if e.request_status_code in [502, 503]: if e.request_status_code in [502, 503]:
self.req_url.change_pull_channel() self._req_url.change_pull_channel()
self.startListening() self.startListening()
else: else:
raise e raise e

View File

@@ -1,7 +0,0 @@
# -*- coding: UTF-8 -*-
"""This file is here to maintain backwards compatability."""
from __future__ import unicode_literals
from .utils import *
from .models import *
from ._client import Client

View File

@@ -1,32 +0,0 @@
# -*- coding: UTF-8 -*-
"""This file is here to maintain backwards compatability."""
from __future__ import unicode_literals
from .models import *
from ._util import (
log,
handler,
USER_AGENTS,
ReqUrl,
facebookEncoding,
now,
strip_to_json,
get_decoded_r,
get_decoded,
parse_json,
get_json,
digitToChar,
str_base,
generateMessageID,
getSignatureID,
generateOfflineThreadingID,
check_json,
check_request,
get_jsmods_require,
require_list,
mimetype_to_key,
get_files_from_urls,
get_files_from_paths,
get_url_parameters,
get_url_parameter,
)