Remove composite methods in Client

- graphql_requests
- graphql_request
- fetch_threads
- fetch_all_users_from_threads
- fetch_user_info
- fetch_page_info
- fetch_group_info

fetch_threads and fetch_all_users_from_threads will be replaced later by
better versions
This commit is contained in:
Mads Marquart
2020-01-09 22:51:56 +01:00
parent 3662fbd038
commit 5e09cb9cab

View File

@@ -56,136 +56,6 @@ class Client:
def __repr__(self):
return "Client(session={!r})".format(self._session)
"""
INTERNAL REQUEST METHODS
"""
def _get(self, url, params):
return self._session._get(url, params)
def _post(self, url, params, files=None):
return self._session._post(url, params, files=files)
def _payload_post(self, url, data, files=None):
return self._session._payload_post(url, data, files=files)
def graphql_requests(self, *queries):
"""Execute GraphQL queries.
Args:
queries (dict): Zero or more dictionaries
Returns:
tuple: A tuple containing JSON GraphQL queries
Raises:
FBchatException: If request failed
"""
return tuple(self._session._graphql_requests(*queries))
def graphql_request(self, query):
"""Shorthand for ``graphql_requests(query)[0]``.
Raises:
FBchatException: If request failed
"""
return self.graphql_requests(query)[0]
"""
END INTERNAL REQUEST METHODS
"""
"""
FETCH METHODS
"""
def fetch_threads(self, thread_location, before=None, after=None, limit=None):
"""Fetch all threads in ``thread_location``.
Threads will be sorted from newest to oldest.
Args:
thread_location (ThreadLocation): INBOX, PENDING, ARCHIVED or OTHER
before (datetime.datetime): Fetch only threads before this (default all
threads). Must be timezone-aware!
after (datetime.datetime): Fetch only threads after this (default all
threads). Must be timezone-aware!
limit: The max. amount of threads to fetch (default all threads)
Returns:
list: `Thread` objects
Raises:
FBchatException: If request failed
"""
threads = []
last_thread_dt = None
while True:
# break if limit is exceeded
if limit and len(threads) >= limit:
break
# fetch_thread_list returns at max 20 threads before last_thread_dt (included)
candidates = self.fetch_thread_list(
before=last_thread_dt, thread_location=thread_location
)
if len(candidates) > 1:
threads += candidates[1:]
else: # End of threads
break
last_thread_dt = threads[-1].last_active
# FB returns a sorted list of threads
if (before is not None and last_thread_dt > before) or (
after is not None and last_thread_dt < after
):
break
# Return only threads between before and after (if set)
if before is not None or after is not None:
for t in threads:
if (before is not None and t.last_active > before) or (
after is not None and t.last_active < after
):
threads.remove(t)
if limit and len(threads) > limit:
return threads[:limit]
return threads
def fetch_all_users_from_threads(self, threads):
"""Fetch all users involved in given threads.
Args:
threads: Thread: List of threads to check for users
Returns:
list: `User` objects
Raises:
FBchatException: If request failed
"""
users = []
users_to_fetch = [] # It's more efficient to fetch all users in one request
for thread in threads:
if isinstance(thread, User):
if thread.id not in [user.id for user in users]:
users.append(thread)
elif isinstance(thread, Group):
for user_id in thread.participants:
if (
user_id not in [user.id for user in users]
and user_id not in users_to_fetch
):
users_to_fetch.append(user_id)
for user_id, user in self.fetch_user_info(*users_to_fetch).items():
users.append(user)
return users
def fetch_users(self) -> Sequence[_user.UserData]:
"""Fetch users the client is currently chatting with.
@@ -222,7 +92,9 @@ class Client:
FBchatException: If request failed
"""
params = {"search": name, "limit": limit}
(j,) = self.graphql_requests(_graphql.from_query(_graphql.SEARCH_USER, params))
(j,) = self.session._graphql_requests(
_graphql.from_query(_graphql.SEARCH_USER, params)
)
return [
UserData._from_graphql(self.session, node)
@@ -242,7 +114,9 @@ class Client:
FBchatException: If request failed
"""
params = {"search": name, "limit": limit}
(j,) = self.graphql_requests(_graphql.from_query(_graphql.SEARCH_PAGE, params))
(j,) = self.session._graphql_requests(
_graphql.from_query(_graphql.SEARCH_PAGE, params)
)
return [
PageData._from_graphql(self.session, node)
@@ -263,7 +137,9 @@ class Client:
FBchatException: If request failed
"""
params = {"search": name, "limit": limit}
(j,) = self.graphql_requests(_graphql.from_query(_graphql.SEARCH_GROUP, params))
(j,) = self.session._graphql_requests(
_graphql.from_query(_graphql.SEARCH_GROUP, params)
)
return [
GroupData._from_graphql(self.session, node)
@@ -284,7 +160,7 @@ class Client:
FBchatException: If request failed
"""
params = {"search": name, "limit": limit}
(j,) = self.graphql_requests(
(j,) = self.session._graphql_requests(
_graphql.from_query(_graphql.SEARCH_THREAD, params)
)
@@ -323,7 +199,7 @@ class Client:
FBchatException: If request failed
"""
data = {"query": query, "snippetLimit": thread_limit}
j = self._payload_post("/ajax/mercury/search_snippets.php?dpr=1", data)
j = self.session._payload_post("/ajax/mercury/search_snippets.php?dpr=1", data)
result = j["search_snippets"][query]
if not result:
@@ -341,7 +217,7 @@ class Client:
def _fetch_info(self, *ids):
data = {"ids[{}]".format(i): _id for i, _id in enumerate(ids)}
j = self._payload_post("/chat/user_info/", data)
j = self.session._payload_post("/chat/user_info/", data)
if j.get("profiles") is None:
raise FBchatException("No users/pages returned: {}".format(j))
@@ -374,78 +250,6 @@ class Client:
log.debug(entries)
return entries
def fetch_user_info(self, *user_ids):
"""Fetch users' info from IDs, unordered.
Warning:
Sends two requests, to fetch all available info!
Args:
user_ids: One or more user ID(s) to query
Returns:
dict: `User` objects, labeled by their ID
Raises:
FBchatException: If request failed
"""
threads = self.fetch_thread_info(*user_ids)
users = {}
for id_, thread in threads.items():
if isinstance(thread, User):
users[id_] = thread
else:
raise ValueError("Thread {} was not a user".format(thread))
return users
def fetch_page_info(self, *page_ids):
"""Fetch pages' info from IDs, unordered.
Warning:
Sends two requests, to fetch all available info!
Args:
page_ids: One or more page ID(s) to query
Returns:
dict: `Page` objects, labeled by their ID
Raises:
FBchatException: If request failed
"""
threads = self.fetch_thread_info(*page_ids)
pages = {}
for id_, thread in threads.items():
if isinstance(thread, Page):
pages[id_] = thread
else:
raise ValueError("Thread {} was not a page".format(thread))
return pages
def fetch_group_info(self, *group_ids):
"""Fetch groups' info from IDs, unordered.
Args:
group_ids: One or more group ID(s) to query
Returns:
dict: `Group` objects, labeled by their ID
Raises:
FBchatException: If request failed
"""
threads = self.fetch_thread_info(*group_ids)
groups = {}
for id_, thread in threads.items():
if isinstance(thread, Group):
groups[id_] = thread
else:
raise ValueError("Thread {} was not a group".format(thread))
return groups
def fetch_thread_info(self, *thread_ids):
"""Fetch threads' info from IDs, unordered.
@@ -472,7 +276,7 @@ class Client:
}
queries.append(_graphql.from_doc_id("2147762685294928", params))
j = self.graphql_requests(*queries)
j = self.session._graphql_requests(*queries)
for i, entry in enumerate(j):
if entry.get("message_thread") is None:
@@ -544,7 +348,9 @@ class Client:
"includeDeliveryReceipts": True,
"includeSeqID": False,
}
(j,) = self.graphql_requests(_graphql.from_doc_id("1349387578499440", params))
(j,) = self.session._graphql_requests(
_graphql.from_doc_id("1349387578499440", params)
)
rtn = []
for node in j["viewer"]["message_threads"]["nodes"]:
@@ -576,7 +382,7 @@ class Client:
"last_action_timestamp": _util.now() - 60 * 1000
# 'last_action_timestamp': 0
}
j = self._payload_post("/ajax/mercury/unread_threads.php", form)
j = self.session._payload_post("/ajax/mercury/unread_threads.php", form)
result = j["unread_thread_fbids"][0]
return result["thread_fbids"] + result["other_user_fbids"]
@@ -590,7 +396,7 @@ class Client:
Raises:
FBchatException: If request failed
"""
j = self._payload_post("/mercury/unseen_thread_ids/", {})
j = self.session._payload_post("/mercury/unseen_thread_ids/", {})
result = j["unseen_thread_fbids"][0]
return result["thread_fbids"] + result["other_user_fbids"]
@@ -609,7 +415,7 @@ class Client:
"""
image_id = str(image_id)
data = {"photo_id": str(image_id)}
j = self._post("/mercury/attachments/photo/", data)
j = self.session._post("/mercury/attachments/photo/", data)
_util.handle_payload_error(j)
url = _util.get_jsmods_require(j, 3)
@@ -618,7 +424,9 @@ class Client:
return url
def _get_private_data(self):
(j,) = self.graphql_requests(_graphql.from_doc_id("1868889766468115", {}))
(j,) = self.session._graphql_requests(
_graphql.from_doc_id("1868889766468115", {})
)
return j["viewer"]
def get_phone_numbers(self):
@@ -657,10 +465,6 @@ class Client:
"""
return self._buddylist.get(str(user_id))
"""
END FETCH METHODS
"""
def mark_as_delivered(self, thread_id, message_id):
"""Mark a message as delivered.
@@ -679,7 +483,7 @@ class Client:
"thread_ids[%s][0]" % thread_id: message_id,
}
j = self._payload_post("/ajax/mercury/delivery_receipts.php", data)
j = self.session._payload_post("/ajax/mercury/delivery_receipts.php", data)
return True
def _read_status(self, read, thread_ids, timestamp=None):
@@ -695,7 +499,7 @@ class Client:
for thread_id in thread_ids:
data["ids[{}]".format(thread_id)] = "true" if read else "false"
j = self._payload_post("/ajax/mercury/change_read_status.php", data)
j = self.session._payload_post("/ajax/mercury/change_read_status.php", data)
def mark_as_read(self, thread_ids=None, timestamp=None):
"""Mark threads as read.
@@ -730,7 +534,7 @@ class Client:
Todo:
Documenting this
"""
j = self._payload_post(
j = self.session._payload_post(
"/ajax/mercury/mark_seen.php", {"seen_timestamp": _util.now()}
)
@@ -758,17 +562,17 @@ class Client:
for thread_id in thread_ids:
data_archive["ids[{}]".format(thread_id)] = "true"
data_unpin["ids[{}]".format(thread_id)] = "false"
j_archive = self._payload_post(
j_archive = self.session._payload_post(
"/ajax/mercury/change_archived_status.php?dpr=1", data_archive
)
j_unpin = self._payload_post(
j_unpin = self.session._payload_post(
"/ajax/mercury/change_pinned_status.php?dpr=1", data_unpin
)
else:
data = dict()
for i, thread_id in enumerate(thread_ids):
data["{}[{}]".format(location.name.lower(), i)] = thread_id
j = self._payload_post("/ajax/mercury/move_thread.php", data)
j = self.session._payload_post("/ajax/mercury/move_thread.php", data)
return True
def delete_threads(self, thread_ids):
@@ -790,10 +594,10 @@ class Client:
for i, thread_id in enumerate(thread_ids):
data_unpin["ids[{}]".format(thread_id)] = "false"
data_delete["ids[{}]".format(i)] = thread_id
j_unpin = self._payload_post(
j_unpin = self.session._payload_post(
"/ajax/mercury/change_pinned_status.php?dpr=1", data_unpin
)
j_delete = self._payload_post(
j_delete = self.session._payload_post(
"/ajax/mercury/delete_thread.php?dpr=1", data_delete
)
return True
@@ -814,7 +618,7 @@ class Client:
data = dict()
for i, message_id in enumerate(message_ids):
data["message_ids[{}]".format(i)] = message_id
j = self._payload_post("/ajax/mercury/delete_messages.php?dpr=1", data)
j = self.session._payload_post("/ajax/mercury/delete_messages.php?dpr=1", data)
return True
"""
@@ -824,17 +628,17 @@ class Client:
def _ping(self):
data = {
"seq": self._seq,
"channel": "p_" + self._session.user_id,
"clientid": self._session._client_id,
"channel": "p_" + self.session.user_id,
"clientid": self.session._client_id,
"partition": -2,
"cap": 0,
"uid": self._session.user_id,
"uid": self.session.user_id,
"sticky_token": self._sticky,
"sticky_pool": self._pool,
"viewer_uid": self._session.user_id,
"viewer_uid": self.session.user_id,
"state": "active",
}
j = self._get(
j = self.session._get(
"https://{}-edge-chat.facebook.com/active_ping".format(self._pull_channel),
data,
)
@@ -847,10 +651,10 @@ class Client:
"msgs_recv": 0,
"sticky_token": self._sticky,
"sticky_pool": self._pool,
"clientid": self._session._client_id,
"clientid": self.session._client_id,
"state": "active" if self._mark_alive else "offline",
}
j = self._get(
j = self.session._get(
"https://{}-edge-chat.facebook.com/pull".format(self._pull_channel), data
)
_util.handle_payload_error(j)