Skip to content
Merged
76 changes: 76 additions & 0 deletions fbchat/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,82 @@ def _forcedFetch(self, thread_id, mid):
}))
return j

def fetchThreads(self, thread_location, before=None, after=None, limit=None):
"""
Get all threads in thread_location.
Threads will be sorted from newest to oldest.

:param thread_location: models.ThreadLocation: INBOX, PENDING, ARCHIVED or OTHER
:param before: Fetch only thread before this epoch (in ms) (default all threads)
:param after: Fetch only thread after this epoch (in ms) (default all threads)
:param limit: The max. amount of threads to fetch (default all threads)
:return: :class:`models.Thread` objects
:rtype: list
:raises: FBchatException if request failed
"""
threads = []

last_thread_timestamp = None
while True:
# break if limit is exceeded
if limit and len(threads) >= limit:
break

# fetchThreadList returns at max 20 threads before last_thread_timestamp (included)
candidates = self.fetchThreadList(before=last_thread_timestamp,
thread_location=thread_location
)

if len(candidates) > 1:
threads += candidates[1:]
else: # End of threads
break

last_thread_timestamp = threads[-1].last_message_timestamp

# FB returns a sorted list of threads
if (before is not None and int(last_thread_timestamp) > before) or \
(after is not None and int(last_thread_timestamp) < 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:
last_message_timestamp = int(t.last_message_timestamp)
if (before is not None and last_message_timestamp > before) or \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems kinda unclean that this is duplicated further up, is there a way we can refactor, and merge these?

(after is not None and last_message_timestamp < after):
threads.remove(t)

if limit and len(threads) > limit:
return threads[:limit]

return threads

def fetchAllUsersFromThreads(self, threads):
"""
Get all users involved in threads.

:param threads: models.Thread: List of threads to check for users
:return: :class:`models.User` objects
:rtype: list
: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 thread.type == ThreadType.USER:
if thread.uid not in [user.uid for user in users]:
users.append(thread)
elif thread.type == ThreadType.GROUP:
for user_id in thread.participants:
if user_id not in [user.uid for user in users] and user_id not in users_to_fetch:
users_to_fetch.append(user_id)
else:
pass
for user_id, user in self.fetchUserInfo(*users_to_fetch).items():
users.append(user)
return users

def fetchAllUsers(self):
"""
Gets all users the client is currently chatting with
Expand Down
5 changes: 5 additions & 0 deletions tests/test_fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ def test_fetch_thread_list(client1):
assert len(threads) == 2


def test_fetch_threads(client1):
threads = client1.fetchThreads(limit=2)
assert len(threads) == 2


@pytest.mark.parametrize("emoji, emoji_size", EMOJI_LIST)
def test_fetch_message_emoji(client, emoji, emoji_size):
mid = client.sendEmoji(emoji, emoji_size)
Expand Down