Merge pull request #439 from carpedm20/graphql-cleanup

Clean up GraphQL helpers
This commit is contained in:
Mads Marquart
2019-07-02 19:52:16 +02:00
committed by GitHub
2 changed files with 172 additions and 167 deletions

View File

@@ -10,7 +10,7 @@ from mimetypes import guess_type
from collections import OrderedDict
from ._util import *
from .models import *
from ._graphql import graphql_queries_to_json, graphql_response_to_json, GraphQL
from . import _graphql
from ._state import State
import time
import json
@@ -132,7 +132,7 @@ class Client(object):
content = check_request(r)
try:
if as_graphql:
return graphql_response_to_json(content)
return _graphql.response_to_json(content)
else:
j = to_json(content)
# TODO: Remove this, and move it to _payload_post instead
@@ -160,8 +160,8 @@ class Client(object):
def graphql_requests(self, *queries):
"""
:param queries: Zero or more GraphQL objects
:type queries: GraphQL
:param queries: Zero or more dictionaries
:type queries: dict
:raises: FBchatException if request failed
:return: A tuple containing json graphql queries
@@ -170,7 +170,7 @@ class Client(object):
data = {
"method": "GET",
"response_format": "json",
"queries": graphql_queries_to_json(*queries),
"queries": _graphql.queries_to_json(*queries),
}
return tuple(self._post("/api/graphqlbatch/", data, as_graphql=True))
@@ -326,7 +326,7 @@ class Client(object):
def _forcedFetch(self, thread_id, mid):
params = {"thread_and_message_id": {"thread_id": thread_id, "message_id": mid}}
return self.graphql_request(GraphQL(doc_id="1768656253222505", params=params))
return self.graphql_request(_graphql.from_doc_id("1768656253222505", params))
def fetchThreads(self, thread_location, before=None, after=None, limit=None):
"""
@@ -438,7 +438,7 @@ class Client(object):
:raises: FBchatException if request failed
"""
params = {"search": name, "limit": limit}
j = self.graphql_request(GraphQL(query=GraphQL.SEARCH_USER, params=params))
j = self.graphql_request(_graphql.from_query(_graphql.SEARCH_USER, params))
return [User._from_graphql(node) for node in j[name]["users"]["nodes"]]
@@ -452,7 +452,7 @@ class Client(object):
:raises: FBchatException if request failed
"""
params = {"search": name, "limit": limit}
j = self.graphql_request(GraphQL(query=GraphQL.SEARCH_PAGE, params=params))
j = self.graphql_request(_graphql.from_query(_graphql.SEARCH_PAGE, params))
return [Page._from_graphql(node) for node in j[name]["pages"]["nodes"]]
@@ -467,7 +467,7 @@ class Client(object):
:raises: FBchatException if request failed
"""
params = {"search": name, "limit": limit}
j = self.graphql_request(GraphQL(query=GraphQL.SEARCH_GROUP, params=params))
j = self.graphql_request(_graphql.from_query(_graphql.SEARCH_GROUP, params))
return [Group._from_graphql(node) for node in j["viewer"]["groups"]["nodes"]]
@@ -482,7 +482,7 @@ class Client(object):
:raises: FBchatException if request failed
"""
params = {"search": name, "limit": limit}
j = self.graphql_request(GraphQL(query=GraphQL.SEARCH_THREAD, params=params))
j = self.graphql_request(_graphql.from_query(_graphql.SEARCH_THREAD, params))
rtn = []
for node in j[name]["threads"]["nodes"]:
@@ -708,7 +708,7 @@ class Client(object):
"load_read_receipts": False,
"before": None,
}
queries.append(GraphQL(doc_id="2147762685294928", params=params))
queries.append(_graphql.from_doc_id("2147762685294928", params))
j = self.graphql_requests(*queries)
@@ -773,7 +773,7 @@ class Client(object):
"load_read_receipts": True,
"before": before,
}
j = self.graphql_request(GraphQL(doc_id="1860982147341344", params=params))
j = self.graphql_request(_graphql.from_doc_id("1860982147341344", params))
if j.get("message_thread") is None:
raise FBchatException("Could not fetch thread {}: {}".format(thread_id, j))
@@ -830,7 +830,7 @@ class Client(object):
"includeDeliveryReceipts": True,
"includeSeqID": False,
}
j = self.graphql_request(GraphQL(doc_id="1349387578499440", params=params))
j = self.graphql_request(_graphql.from_doc_id("1349387578499440", params))
rtn = []
for node in j["viewer"]["message_threads"]["nodes"]:
@@ -935,7 +935,7 @@ class Client(object):
return Plan._from_fetch(j)
def _getPrivateData(self):
j = self.graphql_request(GraphQL(doc_id="1868889766468115"))
j = self.graphql_request(_graphql.from_doc_id("1868889766468115", {}))
return j["viewer"]
def getPhoneNumbers(self):
@@ -1577,7 +1577,7 @@ class Client(object):
"surface": "ADMIN_MODEL_APPROVAL_CENTER",
}
j = self.graphql_request(
GraphQL(doc_id="1574519202665847", params={"data": data})
_graphql.from_doc_id("1574519202665847", {"data": data})
)
def acceptUsersToGroup(self, user_ids, thread_id=None):

View File

@@ -4,7 +4,7 @@ from __future__ import unicode_literals
import json
import re
from . import _util
from ._exception import FBchatException, FBchatUserError
from ._exception import FBchatException
# Shameless copy from https://stackoverflow.com/a/8730674
FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
@@ -27,17 +27,17 @@ class ConcatJSONDecoder(json.JSONDecoder):
# End shameless copy
def graphql_queries_to_json(*queries):
def queries_to_json(*queries):
"""
Queries should be a list of GraphQL objects
"""
rtn = {}
for i, query in enumerate(queries):
rtn["q{}".format(i)] = query.value
rtn["q{}".format(i)] = query
return json.dumps(rtn)
def graphql_response_to_json(content):
def response_to_json(content):
content = _util.strip_json_cruft(content) # Usually only needed in some error cases
try:
j = json.loads(content, cls=ConcatJSONDecoder)
@@ -62,171 +62,176 @@ def graphql_response_to_json(content):
return rtn
class GraphQL(object):
def __init__(self, query=None, doc_id=None, params=None):
if params is None:
params = {}
if query is not None:
self.value = {"priority": 0, "q": query, "query_params": params}
elif doc_id is not None:
self.value = {"doc_id": doc_id, "query_params": params}
else:
raise FBchatUserError("A query or doc_id must be specified")
def from_query(query, params):
return {"priority": 0, "q": query, "query_params": params}
FRAGMENT_USER = """
QueryFragment User: User {
id,
name,
first_name,
last_name,
profile_picture.width(<pic_size>).height(<pic_size>) {
uri
},
is_viewer_friend,
url,
gender,
viewer_affinity
}
"""
FRAGMENT_GROUP = """
QueryFragment Group: MessageThread {
name,
thread_key {
thread_fbid
},
image {
uri
},
is_group_thread,
all_participants {
nodes {
messaging_actor {
id
}
def from_query_id(query_id, params):
return {"query_id": query_id, "query_params": params}
def from_doc(doc, params):
return {"doc": doc, "query_params": params}
def from_doc_id(doc_id, params):
return {"doc_id": doc_id, "query_params": params}
FRAGMENT_USER = """
QueryFragment User: User {
id,
name,
first_name,
last_name,
profile_picture.width(<pic_size>).height(<pic_size>) {
uri
},
is_viewer_friend,
url,
gender,
viewer_affinity
}
"""
FRAGMENT_GROUP = """
QueryFragment Group: MessageThread {
name,
thread_key {
thread_fbid
},
image {
uri
},
is_group_thread,
all_participants {
nodes {
messaging_actor {
id
}
}
},
customization_info {
participant_customizations {
participant_id,
nickname
},
customization_info {
participant_customizations {
participant_id,
nickname
outgoing_bubble_color,
emoji
},
thread_admins {
id
},
group_approval_queue {
nodes {
requester {
id
}
}
},
approval_mode,
joinable_mode {
mode,
link
},
event_reminders {
nodes {
id,
lightweight_event_creator {
id
},
outgoing_bubble_color,
emoji
},
thread_admins {
id
},
group_approval_queue {
time,
location_name,
event_title,
event_reminder_members {
edges {
node {
id
},
guest_list_state
}
}
}
}
}
"""
FRAGMENT_PAGE = """
QueryFragment Page: Page {
id,
name,
profile_picture.width(32).height(32) {
uri
},
url,
category_type,
city {
name
}
}
"""
SEARCH_USER = (
"""
Query SearchUser(<search> = '', <limit> = 10) {
entities_named(<search>) {
search_results.of_type(user).first(<limit>) as users {
nodes {
requester {
id
}
@User
}
},
approval_mode,
joinable_mode {
mode,
link
},
event_reminders {
}
}
}
"""
+ FRAGMENT_USER
)
SEARCH_GROUP = (
"""
Query SearchGroup(<search> = '', <limit> = 10, <pic_size> = 32) {
viewer() {
message_threads.with_thread_name(<search>).last(<limit>) as groups {
nodes {
id,
lightweight_event_creator {
id
},
time,
location_name,
event_title,
event_reminder_members {
edges {
node {
id
},
guest_list_state
}
}
@Group
}
}
}
"""
}
"""
+ FRAGMENT_GROUP
)
FRAGMENT_PAGE = """
QueryFragment Page: Page {
id,
name,
profile_picture.width(32).height(32) {
uri
},
url,
category_type,
city {
name
}
}
SEARCH_PAGE = (
"""
SEARCH_USER = (
"""
Query SearchUser(<search> = '', <limit> = 10) {
entities_named(<search>) {
search_results.of_type(user).first(<limit>) as users {
nodes {
@User
}
Query SearchPage(<search> = '', <limit> = 10) {
entities_named(<search>) {
search_results.of_type(page).first(<limit>) as pages {
nodes {
@Page
}
}
}
"""
+ FRAGMENT_USER
)
}
"""
+ FRAGMENT_PAGE
)
SEARCH_GROUP = (
"""
Query SearchGroup(<search> = '', <limit> = 10, <pic_size> = 32) {
viewer() {
message_threads.with_thread_name(<search>).last(<limit>) as groups {
nodes {
@Group
}
SEARCH_THREAD = (
"""
Query SearchThread(<search> = '', <limit> = 10) {
entities_named(<search>) {
search_results.first(<limit>) as threads {
nodes {
__typename,
@User,
@Group,
@Page
}
}
}
"""
+ FRAGMENT_GROUP
)
SEARCH_PAGE = (
"""
Query SearchPage(<search> = '', <limit> = 10) {
entities_named(<search>) {
search_results.of_type(page).first(<limit>) as pages {
nodes {
@Page
}
}
}
}
"""
+ FRAGMENT_PAGE
)
SEARCH_THREAD = (
"""
Query SearchThread(<search> = '', <limit> = 10) {
entities_named(<search>) {
search_results.first(<limit>) as threads {
nodes {
__typename,
@User,
@Group,
@Page
}
}
}
}
"""
+ FRAGMENT_USER
+ FRAGMENT_GROUP
+ FRAGMENT_PAGE
)
}
"""
+ FRAGMENT_USER
+ FRAGMENT_GROUP
+ FRAGMENT_PAGE
)