From 2d027af71a01b3bee6039d01e8bc132d1b86ceeb Mon Sep 17 00:00:00 2001 From: Tang Date: Tue, 3 Oct 2017 01:14:00 +0800 Subject: [PATCH 1/2] Enable fetching pending/archived threads Add "type" parameter to fetchThreadList(). type can be 'inbox', 'pending' or 'archived' If set to 'pending', it can fetch messages from unknown users. It is quite useful to build a service accepting requests from anyone. For example, in doOneListen(), fetch pending messages once for a while to handle the messages from strangers. --- fbchat/client.py | 49 ++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index 778849a..a8f9c86 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -748,11 +748,12 @@ class Client(object): return list(reversed([graphql_to_message(message) for message in j['message_thread']['messages']['nodes']])) - def fetchThreadList(self, offset=0, limit=20): + def fetchThreadList(self, offset=0, limit=20, type='inbox'): """Get thread list of your facebook account :param offset: The offset, from where in the list to recieve threads from :param limit: Max. number of threads to retrieve. Capped at 20 + :param type: (optional) "inbox", "pending", "archived" :type offset: int :type limit: int :return: :class:`models.Thread` objects @@ -763,10 +764,16 @@ class Client(object): if limit > 20 or limit < 1: raise FBchatUserError('`limit` should be between 1 and 20') + if type in ['inbox', 'pending', 'archived']: + if type == 'archived': + type = 'action:archived' + else: + raise ValueError('thread_type must be "inbox", "pending" or "archived"') + data = { 'client' : self.client, - 'inbox[offset]' : offset, - 'inbox[limit]' : limit, + type + '[offset]' : offset, + type + '[limit]' : limit, } j = self._post(self.req_url.THREADS, data, fix_request=True, as_json=True) @@ -774,25 +781,27 @@ class Client(object): raise FBchatException('Missing payload: {}, with data: {}'.format(j, data)) participants = {} - for p in j['payload']['participants']: - if p['type'] == 'page': - participants[p['fbid']] = Page(p['fbid'], url=p['href'], photo=p['image_src'], name=p['name']) - elif p['type'] == 'user': - participants[p['fbid']] = User(p['fbid'], url=p['href'], first_name=p['short_name'], is_friend=p['is_friend'], gender=GENDERS[p['gender']], photo=p['image_src'], name=p['name']) - else: - raise FBchatException('A participant had an unknown type {}: {}'.format(p['type'], p)) + if 'participants' in j['payload']: + for p in j['payload']['participants']: + if p['type'] == 'page': + participants[p['fbid']] = Page(p['fbid'], url=p['href'], photo=p['image_src'], name=p['name']) + elif p['type'] == 'user': + participants[p['fbid']] = User(p['fbid'], url=p['href'], first_name=p['short_name'], is_friend=p['is_friend'], gender=GENDERS[p['gender']], photo=p['image_src'], name=p['name']) + else: + raise FBchatException('A participant had an unknown type {}: {}'.format(p['type'], p)) entries = [] - for k in j['payload']['threads']: - if k['thread_type'] == 1: - if k['other_user_fbid'] not in participants: - raise FBchatException('The thread {} was not in participants: {}'.format(k, j['payload'])) - participants[k['other_user_fbid']].message_count = k['message_count'] - entries.append(participants[k['other_user_fbid']]) - elif k['thread_type'] == 2: - entries.append(Group(k['thread_fbid'], participants=set([p.strip('fbid:') for p in k['participants']]), photo=k['image_src'], name=k['name'], message_count=k['message_count'])) - else: - raise FBchatException('A thread had an unknown thread type: {}'.format(k)) + if 'threads' in j['payload']: + for k in j['payload']['threads']: + if k['thread_type'] == 1: + if k['other_user_fbid'] not in participants: + raise FBchatException('The thread {} was not in participants: {}'.format(k, j['payload'])) + participants[k['other_user_fbid']].message_count = k['message_count'] + entries.append(participants[k['other_user_fbid']]) + elif k['thread_type'] == 2: + entries.append(Group(k['thread_fbid'], participants=set([p.strip('fbid:') for p in k['participants']]), photo=k['image_src'], name=k['name'], message_count=k['message_count'])) + else: + raise FBchatException('A thread had an unknown thread type: {}'.format(k)) return entries From 8eb6b83411438fc87772559e1bd295ff0da2b620 Mon Sep 17 00:00:00 2001 From: Tang Date: Tue, 3 Oct 2017 03:05:08 +0800 Subject: [PATCH 2/2] Update for feedback by @madsmtm 1. Add ThreadLocation Enum in models. 2. avoid using build-in name "type" as parameter name 3. replace ValueError with FBchatUserError thanks to @madsmtm --- fbchat/client.py | 15 +++++++-------- fbchat/models.py | 7 +++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index a8f9c86..3e1bbab 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -748,12 +748,12 @@ class Client(object): return list(reversed([graphql_to_message(message) for message in j['message_thread']['messages']['nodes']])) - def fetchThreadList(self, offset=0, limit=20, type='inbox'): + def fetchThreadList(self, offset=0, limit=20, thread_location=ThreadLocation.INBOX): """Get thread list of your facebook account :param offset: The offset, from where in the list to recieve threads from :param limit: Max. number of threads to retrieve. Capped at 20 - :param type: (optional) "inbox", "pending", "archived" + :param thread_location: models.ThreadLocation: INBOX, PENDING, ARCHIVED or OTHER :type offset: int :type limit: int :return: :class:`models.Thread` objects @@ -764,16 +764,15 @@ class Client(object): if limit > 20 or limit < 1: raise FBchatUserError('`limit` should be between 1 and 20') - if type in ['inbox', 'pending', 'archived']: - if type == 'archived': - type = 'action:archived' + if thread_location in ThreadLocation: + loc_str = thread_location.value else: - raise ValueError('thread_type must be "inbox", "pending" or "archived"') + raise FBchatUserError('"thread_location" must be a value of ThreadLocation') data = { 'client' : self.client, - type + '[offset]' : offset, - type + '[limit]' : limit, + loc_str + '[offset]' : offset, + loc_str + '[limit]' : limit, } j = self._post(self.req_url.THREADS, data, fix_request=True, as_json=True) diff --git a/fbchat/models.py b/fbchat/models.py index c61ceb1..4894cd2 100644 --- a/fbchat/models.py +++ b/fbchat/models.py @@ -193,6 +193,13 @@ class ThreadType(Enum): GROUP = 2 PAGE = 3 +class ThreadLocation(Enum): + """Used to specify where a thread is located (inbox, pending, archived, other).""" + INBOX = 'inbox' + PENDING = 'pending' + ARCHIVED = 'action:archived' + OTHER = 'other' + class TypingStatus(Enum): """Used to specify whether the user is typing or has stopped typing""" STOPPED = 0