Add session attribute to Group/User/Page/Thread

This commit is contained in:
Mads Marquart
2020-01-08 23:07:13 +01:00
parent a5abb05ab3
commit 0531a9e482
9 changed files with 71 additions and 30 deletions

View File

@@ -61,6 +61,10 @@ class Client:
self._buddylist = dict() self._buddylist = dict()
self._session = session self._session = session
@property
def session(self):
return self._session
""" """
INTERNAL REQUEST METHODS INTERNAL REQUEST METHODS
""" """
@@ -214,7 +218,7 @@ class Client:
if data["id"] in ["0", 0]: if data["id"] in ["0", 0]:
# Skip invalid users # Skip invalid users
continue continue
users.append(User._from_all_fetch(data)) users.append(User._from_all_fetch(self.session, data))
return users return users
def search_for_users(self, name, limit=10): def search_for_users(self, name, limit=10):
@@ -233,7 +237,9 @@ class Client:
params = {"search": name, "limit": limit} params = {"search": name, "limit": limit}
(j,) = self.graphql_requests(_graphql.from_query(_graphql.SEARCH_USER, params)) (j,) = self.graphql_requests(_graphql.from_query(_graphql.SEARCH_USER, params))
return [User._from_graphql(node) for node in j[name]["users"]["nodes"]] return [
User._from_graphql(self.session, node) for node in j[name]["users"]["nodes"]
]
def search_for_pages(self, name, limit=10): def search_for_pages(self, name, limit=10):
"""Find and get pages by their name. """Find and get pages by their name.
@@ -250,7 +256,9 @@ class Client:
params = {"search": name, "limit": limit} params = {"search": name, "limit": limit}
(j,) = self.graphql_requests(_graphql.from_query(_graphql.SEARCH_PAGE, params)) (j,) = self.graphql_requests(_graphql.from_query(_graphql.SEARCH_PAGE, params))
return [Page._from_graphql(node) for node in j[name]["pages"]["nodes"]] return [
Page._from_graphql(self.session, node) for node in j[name]["pages"]["nodes"]
]
def search_for_groups(self, name, limit=10): def search_for_groups(self, name, limit=10):
"""Find and get group threads by their name. """Find and get group threads by their name.
@@ -268,7 +276,10 @@ class Client:
params = {"search": name, "limit": limit} params = {"search": name, "limit": limit}
(j,) = self.graphql_requests(_graphql.from_query(_graphql.SEARCH_GROUP, params)) (j,) = self.graphql_requests(_graphql.from_query(_graphql.SEARCH_GROUP, params))
return [Group._from_graphql(node) for node in j["viewer"]["groups"]["nodes"]] return [
Group._from_graphql(self.session, node)
for node in j["viewer"]["groups"]["nodes"]
]
def search_for_threads(self, name, limit=10): def search_for_threads(self, name, limit=10):
"""Find and get threads by their name. """Find and get threads by their name.
@@ -291,12 +302,12 @@ class Client:
rtn = [] rtn = []
for node in j[name]["threads"]["nodes"]: for node in j[name]["threads"]["nodes"]:
if node["__typename"] == "User": if node["__typename"] == "User":
rtn.append(User._from_graphql(node)) rtn.append(User._from_graphql(self.session, node))
elif node["__typename"] == "MessageThread": elif node["__typename"] == "MessageThread":
# MessageThread => Group thread # MessageThread => Group thread
rtn.append(Group._from_graphql(node)) rtn.append(Group._from_graphql(self.session, node))
elif node["__typename"] == "Page": elif node["__typename"] == "Page":
rtn.append(Page._from_graphql(node)) rtn.append(Page._from_graphql(self.session, node))
elif node["__typename"] == "Group": elif node["__typename"] == "Group":
# We don't handle Facebook "Groups" # We don't handle Facebook "Groups"
pass pass
@@ -551,16 +562,16 @@ class Client:
entry = entry["message_thread"] entry = entry["message_thread"]
if entry.get("thread_type") == "GROUP": if entry.get("thread_type") == "GROUP":
_id = entry["thread_key"]["thread_fbid"] _id = entry["thread_key"]["thread_fbid"]
rtn[_id] = Group._from_graphql(entry) rtn[_id] = Group._from_graphql(self.session, entry)
elif entry.get("thread_type") == "ONE_TO_ONE": elif entry.get("thread_type") == "ONE_TO_ONE":
_id = entry["thread_key"]["other_user_id"] _id = entry["thread_key"]["other_user_id"]
if pages_and_users.get(_id) is None: if pages_and_users.get(_id) is None:
raise FBchatException("Could not fetch thread {}".format(_id)) raise FBchatException("Could not fetch thread {}".format(_id))
entry.update(pages_and_users[_id]) entry.update(pages_and_users[_id])
if entry["type"] == ThreadType.USER: if entry["type"] == ThreadType.USER:
rtn[_id] = User._from_graphql(entry) rtn[_id] = User._from_graphql(self.session, entry)
else: else:
rtn[_id] = Page._from_graphql(entry) rtn[_id] = Page._from_graphql(self.session, entry)
else: else:
raise FBchatException( raise FBchatException(
"{} had an unknown thread type: {}".format(thread_ids[i], entry) "{} had an unknown thread type: {}".format(thread_ids[i], entry)
@@ -641,9 +652,9 @@ class Client:
for node in j["viewer"]["message_threads"]["nodes"]: for node in j["viewer"]["message_threads"]["nodes"]:
_type = node.get("thread_type") _type = node.get("thread_type")
if _type == "GROUP": if _type == "GROUP":
rtn.append(Group._from_graphql(node)) rtn.append(Group._from_graphql(self.session, node))
elif _type == "ONE_TO_ONE": elif _type == "ONE_TO_ONE":
rtn.append(User._from_thread_fetch(node)) rtn.append(User._from_thread_fetch(self.session, node))
else: else:
raise FBchatException( raise FBchatException(
"Unknown thread type: {}, with data: {}".format(_type, node) "Unknown thread type: {}, with data: {}".format(_type, node)

View File

@@ -1,6 +1,6 @@
import attr import attr
from ._core import attrs_default, Image from ._core import attrs_default, Image
from . import _util, _plan from . import _util, _session, _plan
from ._thread import ThreadType, Thread from ._thread import ThreadType, Thread
@@ -10,6 +10,10 @@ class Group(Thread):
type = ThreadType.GROUP type = ThreadType.GROUP
#: The session to use when making requests.
session = attr.ib(type=_session.Session)
#: The group's unique identifier.
id = attr.ib(converter=str)
#: The group's picture #: The group's picture
photo = attr.ib(None) photo = attr.ib(None)
#: The name of the group #: The name of the group
@@ -38,7 +42,7 @@ class Group(Thread):
join_link = attr.ib(None) join_link = attr.ib(None)
@classmethod @classmethod
def _from_graphql(cls, data): def _from_graphql(cls, session, data):
if data.get("image") is None: if data.get("image") is None:
data["image"] = {} data["image"] = {}
c_info = cls._parse_customization_info(data) c_info = cls._parse_customization_info(data)
@@ -52,6 +56,7 @@ class Group(Thread):
plan = _plan.Plan._from_graphql(data["event_reminders"]["nodes"][0]) plan = _plan.Plan._from_graphql(data["event_reminders"]["nodes"][0])
return cls( return cls(
session=session,
id=data["thread_key"]["thread_fbid"], id=data["thread_key"]["thread_fbid"],
participants=set( participants=set(
[ [

View File

@@ -1,6 +1,6 @@
import attr import attr
from ._core import attrs_default, Image from ._core import attrs_default, Image
from . import _plan from . import _session, _plan
from ._thread import ThreadType, Thread from ._thread import ThreadType, Thread
@@ -10,6 +10,10 @@ class Page(Thread):
type = ThreadType.PAGE type = ThreadType.PAGE
#: The session to use when making requests.
session = attr.ib(type=_session.Session)
#: The unique identifier of the page.
id = attr.ib(converter=str)
#: The page's picture #: The page's picture
photo = attr.ib(None) photo = attr.ib(None)
#: The name of the page #: The name of the page
@@ -32,7 +36,7 @@ class Page(Thread):
category = attr.ib(None) category = attr.ib(None)
@classmethod @classmethod
def _from_graphql(cls, data): def _from_graphql(cls, session, data):
if data.get("profile_picture") is None: if data.get("profile_picture") is None:
data["profile_picture"] = {} data["profile_picture"] = {}
if data.get("city") is None: if data.get("city") is None:
@@ -42,6 +46,7 @@ class Page(Thread):
plan = _plan.Plan._from_graphql(data["event_reminders"]["nodes"][0]) plan = _plan.Plan._from_graphql(data["event_reminders"]["nodes"][0])
return cls( return cls(
session=session,
id=data["id"], id=data["id"],
url=data.get("url"), url=data.get("url"),
city=data.get("city").get("name"), city=data.get("city").get("name"),

View File

@@ -1,5 +1,6 @@
import attr import attr
from ._core import attrs_default, Enum, Image from ._core import attrs_default, Enum, Image
from . import _session
class ThreadType(Enum): class ThreadType(Enum):
@@ -71,6 +72,8 @@ class ThreadColor(Enum):
class Thread: class Thread:
"""Represents a Facebook thread.""" """Represents a Facebook thread."""
#: The session to use when making requests.
session = attr.ib(type=_session.Session)
#: The unique identifier of the thread. #: The unique identifier of the thread.
id = attr.ib(converter=str) id = attr.ib(converter=str)
#: Specifies the type of thread. Can be used a ``thread_type``. See :ref:`intro_threads` for more info #: Specifies the type of thread. Can be used a ``thread_type``. See :ref:`intro_threads` for more info

View File

@@ -1,6 +1,6 @@
import attr import attr
from ._core import attrs_default, Enum, Image from ._core import attrs_default, Enum, Image
from . import _util, _plan from . import _util, _session, _plan
from ._thread import ThreadType, Thread from ._thread import ThreadType, Thread
@@ -47,6 +47,10 @@ class User(Thread):
type = ThreadType.USER type = ThreadType.USER
#: The session to use when making requests.
session = attr.ib(type=_session.Session)
#: The user's unique identifier.
id = attr.ib(converter=str)
#: The user's picture #: The user's picture
photo = attr.ib(None) photo = attr.ib(None)
#: The name of the user #: The name of the user
@@ -79,7 +83,7 @@ class User(Thread):
emoji = attr.ib(None) emoji = attr.ib(None)
@classmethod @classmethod
def _from_graphql(cls, data): def _from_graphql(cls, session, data):
if data.get("profile_picture") is None: if data.get("profile_picture") is None:
data["profile_picture"] = {} data["profile_picture"] = {}
c_info = cls._parse_customization_info(data) c_info = cls._parse_customization_info(data)
@@ -88,6 +92,7 @@ class User(Thread):
plan = _plan.Plan._from_graphql(data["event_reminders"]["nodes"][0]) plan = _plan.Plan._from_graphql(data["event_reminders"]["nodes"][0])
return cls( return cls(
session=session,
id=data["id"], id=data["id"],
url=data.get("url"), url=data.get("url"),
first_name=data.get("first_name"), first_name=data.get("first_name"),
@@ -106,7 +111,7 @@ class User(Thread):
) )
@classmethod @classmethod
def _from_thread_fetch(cls, data): def _from_thread_fetch(cls, session, data):
if data.get("big_image_src") is None: if data.get("big_image_src") is None:
data["big_image_src"] = {} data["big_image_src"] = {}
c_info = cls._parse_customization_info(data) c_info = cls._parse_customization_info(data)
@@ -133,6 +138,7 @@ class User(Thread):
plan = _plan.Plan._from_graphql(data["event_reminders"]["nodes"][0]) plan = _plan.Plan._from_graphql(data["event_reminders"]["nodes"][0])
return cls( return cls(
session=session,
id=user["id"], id=user["id"],
url=user.get("url"), url=user.get("url"),
name=user.get("name"), name=user.get("name"),
@@ -152,8 +158,9 @@ class User(Thread):
) )
@classmethod @classmethod
def _from_all_fetch(cls, data): def _from_all_fetch(cls, session, data):
return cls( return cls(
session=session,
id=data["id"], id=data["id"],
first_name=data.get("firstName"), first_name=data.get("firstName"),
url=data.get("uri"), url=data.get("uri"),

View File

@@ -6,6 +6,11 @@ from contextlib import contextmanager
from fbchat import ThreadType, Message, Mention from fbchat import ThreadType, Message, Mention
@pytest.fixture(scope="session")
def session():
return object() # TODO: Add a mocked session
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def user(client2): def user(client2):
return {"id": client2.id, "type": ThreadType.USER} return {"id": client2.id, "type": ThreadType.USER}

View File

@@ -1,7 +1,7 @@
from fbchat._group import Group from fbchat._group import Group
def test_group_from_graphql(): def test_group_from_graphql(session):
data = { data = {
"name": "Group ABC", "name": "Group ABC",
"thread_key": {"thread_fbid": "11223344"}, "thread_key": {"thread_fbid": "11223344"},
@@ -26,6 +26,7 @@ def test_group_from_graphql():
"event_reminders": {"nodes": []}, "event_reminders": {"nodes": []},
} }
assert Group( assert Group(
session=session,
id="11223344", id="11223344",
photo=None, photo=None,
name="Group ABC", name="Group ABC",
@@ -40,4 +41,4 @@ def test_group_from_graphql():
approval_mode=False, approval_mode=False,
approval_requests=set(), approval_requests=set(),
join_link="", join_link="",
) == Group._from_graphql(data) ) == Group._from_graphql(session, data)

View File

@@ -2,7 +2,7 @@ import fbchat
from fbchat._page import Page from fbchat._page import Page
def test_page_from_graphql(): def test_page_from_graphql(session):
data = { data = {
"id": "123456", "id": "123456",
"name": "Some school", "name": "Some school",
@@ -12,10 +12,11 @@ def test_page_from_graphql():
"city": None, "city": None,
} }
assert Page( assert Page(
session=session,
id="123456", id="123456",
photo=fbchat.Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/..."), photo=fbchat.Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/..."),
name="Some school", name="Some school",
url="https://www.facebook.com/some-school/", url="https://www.facebook.com/some-school/",
city=None, city=None,
category="SCHOOL", category="SCHOOL",
) == Page._from_graphql(data) ) == Page._from_graphql(session, data)

View File

@@ -4,7 +4,7 @@ import fbchat
from fbchat._user import User, ActiveStatus from fbchat._user import User, ActiveStatus
def test_user_from_graphql(): def test_user_from_graphql(session):
data = { data = {
"id": "1234", "id": "1234",
"name": "Abc Def Ghi", "name": "Abc Def Ghi",
@@ -17,6 +17,7 @@ def test_user_from_graphql():
"viewer_affinity": 0.4560002, "viewer_affinity": 0.4560002,
} }
assert User( assert User(
session=session,
id="1234", id="1234",
photo=fbchat.Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/..."), photo=fbchat.Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/..."),
name="Abc Def Ghi", name="Abc Def Ghi",
@@ -25,10 +26,10 @@ def test_user_from_graphql():
last_name="Ghi", last_name="Ghi",
is_friend=True, is_friend=True,
gender="female_singular", gender="female_singular",
) == User._from_graphql(data) ) == User._from_graphql(session, data)
def test_user_from_thread_fetch(): def test_user_from_thread_fetch(session):
data = { data = {
"thread_key": {"thread_fbid": None, "other_user_id": "1234"}, "thread_key": {"thread_fbid": None, "other_user_id": "1234"},
"name": None, "name": None,
@@ -137,6 +138,7 @@ def test_user_from_thread_fetch():
"delivery_receipts": ..., "delivery_receipts": ...,
} }
assert User( assert User(
session=session,
id="1234", id="1234",
photo=fbchat.Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/..."), photo=fbchat.Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/..."),
name="Abc Def Ghi", name="Abc Def Ghi",
@@ -151,10 +153,10 @@ def test_user_from_thread_fetch():
own_nickname="B", own_nickname="B",
color=None, color=None,
emoji=None, emoji=None,
) == User._from_thread_fetch(data) ) == User._from_thread_fetch(session, data)
def test_user_from_all_fetch(): def test_user_from_all_fetch(session):
data = { data = {
"id": "1234", "id": "1234",
"name": "Abc Def Ghi", "name": "Abc Def Ghi",
@@ -175,6 +177,7 @@ def test_user_from_all_fetch():
"is_blocked": False, "is_blocked": False,
} }
assert User( assert User(
session=session,
id="1234", id="1234",
photo=fbchat.Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/..."), photo=fbchat.Image(url="https://scontent-arn2-1.xx.fbcdn.net/v/..."),
name="Abc Def Ghi", name="Abc Def Ghi",
@@ -182,7 +185,7 @@ def test_user_from_all_fetch():
first_name="Abc", first_name="Abc",
is_friend=True, is_friend=True,
gender="female_singular", gender="female_singular",
) == User._from_all_fetch(data) ) == User._from_all_fetch(session, data)
@pytest.mark.skip(reason="can't gather test data, the pulling is broken") @pytest.mark.skip(reason="can't gather test data, the pulling is broken")