From f4dec2e48eb2adcaaff412516fa79dc97fe8a82a Mon Sep 17 00:00:00 2001 From: Dainius Date: Tue, 9 May 2017 10:25:04 +0300 Subject: [PATCH 1/2] update send methods --- fbchat/client.py | 294 ++++++++++++++++++++++++----------------------- fbchat/models.py | 6 +- 2 files changed, 152 insertions(+), 148 deletions(-) diff --git a/fbchat/client.py b/fbchat/client.py index d16c136..c21cea0 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -79,7 +79,6 @@ class Client(object): :param session_cookies: Cookie dict from a previous session (Will default to login if these are invalid) """ - self.is_def_recipient_set = False self.sticky, self.pool = (None, None) self._session = requests.session() self.req_counter = 1 @@ -87,6 +86,9 @@ class Client(object): self.payloadDefault = {} self.client = 'mercury' self.listening = False + self.is_def_thread_set = False + self.def_thread_id = None + self.def_thread_type = None self.threads = [] # Setup event hooks @@ -162,24 +164,6 @@ class Client(object): if not session_cookies or not self.setSession(session_cookies) or not self.isLoggedIn(): self.login(email, password, max_retries) - def _console(self, msg): - """Assumes an INFO level and log it. - - This method shouldn't be used anymore. - Use the log itself: - >>> import logging - >>> from fbchat.client import log - >>> log.setLevel(logging.DEBUG) - - You can do the same thing by adding the 'debug' argument: - >>> from fbchat import Client - >>> client = Client("...", "...", debug=True) - """ - warnings.warn( - "Client._console shouldn't be used. Use 'log.'", - DeprecationWarning) - log.debug(msg) - def _generatePayload(self, query): """Adds the following defaults to the payload: __rev, __user, __a, ttstamp, fb_dtsg, __req @@ -355,7 +339,7 @@ class Client(object): return True def login(self, email, password, max_retries=5): - self.onLoggingIn(email) + self.onLoggingIn(email=email) if not (email and password): raise Exception("Email and password not set.") @@ -369,7 +353,7 @@ class Client(object): time.sleep(1) continue else: - self.onLoggedIn(email) + self.onLoggedIn(email=email) break else: raise Exception("Login failed. Check email/password.") @@ -389,15 +373,15 @@ class Client(object): self.seq = "0" return r - def setDefaultRecipient(self, recipient_id, is_user=True): + def setDefaultThreadId(self, thread_id=str, thread_type=ThreadType): """Sets default recipient to send messages and images to. - :param recipient_id: the user id or thread id that you want to send a message to - :param is_user: determines if the recipient_id is for user or thread + :param thread_id: user/group ID to default to + :param thread_type: type of thread_id """ - self.def_recipient_id = recipient_id - self.def_is_user = is_user - self.is_def_recipient_set = True + self.def_thread_id = thread_id + self.def_thread_type = thread_type + self.is_def_thread_set = True def getAllUsers(self): """ Gets all users from chat with info included """ @@ -448,24 +432,27 @@ class Client(object): users.append(User(entry)) return users # have bug TypeError: __repr__ returned non-string (type bytes) - def send(self, recipient_id=None, message=None, is_user=True, like=None, image_id=None, add_user_ids=None): + """ + SEND METHODS + """ + + def _send(self, thread_id=None, message=None, thread_type=None, emoji_size=None, image_id=None, add_user_ids=None, new_title=None): """Send a message with given thread id - :param recipient_id: the user id or thread id that you want to send a message to + :param thread_id: the user id or thread id that you want to send a message to :param message: a text that you want to send - :param is_user: determines if the recipient_id is for user or thread - :param like: size of the like sticker you want to send + :param thread_type: determines if the recipient_id is for user or thread + :param emoji_size: size of the like sticker you want to send :param image_id: id for the image to send, gotten from the UploadURL :param add_user_ids: a list of user ids to add to a chat - - returns a list of message ids of the sent message(s) + :return: a list of message ids of the sent message(s) """ - if self.is_def_recipient_set: - recipient_id = self.def_recipient_id - is_user = self.def_is_user - elif recipient_id is None: - raise Exception('Recipient ID is not set.') + if thread_id is None and self.is_def_thread_set: + thread_id = self.def_thread_id + thread_type = self.def_thread_type + elif thread_id is None and not self.is_def_thread_set: + raise ValueError('Default Thread ID is not set.') messageAndOTID = generateOfflineThreadingID() timestamp = now() @@ -493,37 +480,47 @@ class Client(object): 'status' : '0', 'offline_threading_id':messageAndOTID, 'message_id' : messageAndOTID, - 'threading_id':generateMessageID(self.client_id), + 'threading_id': generateMessageID(self.client_id), 'ephemeral_ttl_mode:': '0', 'manual_retry_cnt' : '0', 'signatureID' : getSignatureID() } - if is_user: - data["other_user_fbid"] = recipient_id - else: - data["thread_fbid"] = recipient_id + # Set recipient + if thread_type == ThreadType.USER: + data["other_user_fbid"] = thread_id + elif thread_type == ThreadType.GROUP: + data["thread_fbid"] = thread_id + # Set title + if new_title: + data['action_type'] = 'ma-type:log-message' + data['log_message_data[name]'] = new_title + data['log_message_type'] = 'log:thread-name' + + # Set users to add if add_user_ids: data['action_type'] = 'ma-type:log-message' # It's possible to add multiple users for i, add_user_id in enumerate(add_user_ids): data['log_message_data[added_participants][' + str(i) + ']'] = "fbid:" + str(add_user_id) data['log_message_type'] = 'log:subscribe' - else: + + # Sending a simple message + if not add_user_ids and not new_title: data['action_type'] = 'ma-type:user-generated-message' - data['body'] = message + data['body'] = message or '' data['has_attachment'] = image_id is not None - data['specific_to_list[0]'] = 'fbid:' + str(recipient_id) + data['specific_to_list[0]'] = 'fbid:' + str(thread_id) data['specific_to_list[1]'] = 'fbid:' + str(self.uid) + # Set image to send if image_id: data['image_ids[0]'] = image_id - if like and not type(like) is Sticker: - data["sticker_id"] = Sticker.SMALL.value - else: - data["sticker_id"] = like.value + # Set emoji to send + if emoji_size: + data["sticker_id"] = emoji_size.value r = self._post(SendURL, data) @@ -531,9 +528,10 @@ class Client(object): log.warning('Error when sending message: Got {} response'.format(r.status_code)) return False - if isinstance(r._content, str) is False: - r._content = r._content.decode(facebookEncoding) - j = get_json(r._content) + response_content = {} + if isinstance(r.content, str) is False: + response_content = r.content.decode(facebookEncoding) + j = get_json(response_content) if 'error' in j: # 'errorDescription' is in the users own language! log.warning('Error #{} when sending message: {}'.format(j['error'], j['errorDescription'])) @@ -552,42 +550,114 @@ class Client(object): log.debug("With data {}".format(data)) return message_ids - def sendRemoteImage(self, recipient_id=None, message=None, is_user=True, image=''): - """Send an image from a URL - - :param recipient_id: the user id or thread id that you want to send a message to - :param message: a text that you want to send - :param is_user: determines if the recipient_id is for user or thread - :param image: URL for an image to download and send + def sendMessage(self, message: str, thread_id: str = None, thread_type: ThreadType = None): """ - mimetype = guess_type(image)[0] - remote_image = requests.get(image).content - image_id = self.uploadImage({'file': (image, remote_image, mimetype)}) - return self.send(recipient_id, message, is_user, None, image_id) - - def sendLocalImage(self, recipient_id=None, message=None, is_user=True, image=''): - """Send an image from a file path - - :param recipient_id: the user id or thread id that you want to send a message to - :param message: a text that you want to send - :param is_user: determines if the recipient_id is for user or thread - :param image: path to a local image to send + Sends a message to given (or default, if not) thread with an additional image. + :param message: message to send + :param thread_id: user/group chat ID + :param thread_type: specify whether thread_id is user or group chat + :return: a list of message ids of the sent message(s) """ - mimetype = guess_type(image)[0] - image_id = self.uploadImage({'file': (image, open(image, 'rb'), mimetype)}) - return self.send(recipient_id, message, is_user, None, image_id) + return self._send(thread_id, message, thread_type, None, None, None, None) - def uploadImage(self, image): + def sendEmoji(self, emoji_size: EmojiSize, thread_id: str = None, thread_type: ThreadType = None): + """ + Sends an emoji to given (or default, if not) thread. + :param emoji_size: size of emoji to send + :param thread_id: user/group chat ID + :param thread_type: specify whether thread_id is user or group chat + :return: a list of message ids of the sent message(s) + """ + return self._send(thread_id, None, thread_type, emoji_size, None, None, None) + + def sendRemoteImage(self, image_url: str, message: str = None, thread_id: str = None, thread_type: ThreadType = None): + """ + Sends an image from given URL to given (or default, if not) thread. + :param image_url: URL of an image to upload and send + :param message: additional message + :param thread_id: user/group chat ID + :param thread_type: specify whether thread_id is user or group chat + :return: a list of message ids of the sent message(s) + """ + mimetype = guess_type(image_url)[0] + remote_image = requests.get(image_url).content + image_id = self._uploadImage({'file': (image_url, remote_image, mimetype)}) + return self._send(thread_id, message, thread_type, None, image_id, None, None) + + # Doesn't upload properly + # def sendLocalImage(self, image_path: str, message: str = None, thread_id: str = None, thread_type: ThreadType = None): + # """ + # Sends an image from given URL to given (or default, if not) thread. + # :param image_path: path of an image to upload and send + # :param message: additional message + # :param thread_id: user/group chat ID + # :param thread_type: specify whether thread_id is user or group chat + # :return: a list of message ids of the sent message(s) + # """ + # mimetype = guess_type(image_path)[0] + # image_id = self._uploadImage({'file': (image_path, open(image_path, 'rb'), mimetype)}) + # return self._send(thread_id, message, thread_type, None, image_id, None, None) + + def addUsersToChat(self, user_list: list, thread_id: str = None): + """ + Adds users to given (or default, if not) thread. + :param user_list: list of users to add + :param thread_id: group chat ID + :return: a list of message ids of the sent message(s) + """ + return self._send(thread_id, None, ThreadType.GROUP, None, None, user_list, None) + + def removeUserFromChat(self, user_id: str, thread_id: str = None): + """ + Adds users to given (or default, if not) thread. + :param user_id: user ID to remove + :param thread_id: group chat ID + :return: true if user was removed + """ + + if thread_id is None and self.def_thread_type == ThreadType.GROUP: + thread_id = self.def_thread_id + elif thread_id is None: + raise ValueError('Default Thread ID is not set.') + + data = { + "uid": user_id, + "tid": thread_id + } + + r = self._post(RemoveUserURL, data) + + return r.ok + + def changeThreadTitle(self, new_title: str, thread_id: str = None): + """ + Change title of a group conversation. + :param new_title: new group chat title + :param thread_id: group chat ID + :return: a list of message ids of the sent message(s) + """ + if thread_id is None and self.def_thread_type == ThreadType.GROUP: + thread_id = self.def_thread_id + elif thread_id is None: + raise ValueError('Default Thread ID is not set.') + return self._send(thread_id, None, ThreadType.GROUP, None, None, None, new_title) + + """ + END SEND METHODS + """ + + def _uploadImage(self, image): """Upload an image and get the image_id for sending in a message :param image: a tuple of (file name, data, mime type) to upload to facebook """ r = self._postFile(UploadURL, image) - if isinstance(r._content, str) is False: - r._content = r._content.decode(facebookEncoding) + response_content = {} + if isinstance(r.content, str) is False: + response_content = r.content.decode(facebookEncoding) # Strip the start and parse out the returned image_id - return json.loads(r._content[9:])['payload']['metadata'][0]['image_id'] + return json.loads(response_content[9:])['payload']['metadata'][0]['image_id'] def getThreadInfo(self, userID, last_n=20, start=None, is_user=True): """Get the info of one Thread @@ -963,69 +1033,3 @@ class Client(object): if len(full_data)==1: full_data=full_data[0] return full_data - - def removeUserFromChat(self, threadID, userID): - """Remove user (userID) from group chat (threadID) - - :param threadID: group chat id - :param userID: user id to remove from chat - """ - - data = { - "uid" : userID, - "tid" : threadID - } - - r = self._post(RemoveUserURL, data) - - return r.ok - - def addUserToChat(self, threadID, userID): - """Add user (userID) to group chat (threadID) - - :param threadID: group chat id - :param userID: user id to add to chat - """ - return self.send(threadID, is_user=False, add_user_ids=[userID]) - - def changeThreadTitle(self, threadID, newTitle): - """Change title of a group conversation - - :param threadID: group chat id - :param newTitle: new group chat title - """ - - messageAndOTID = generateOfflineThreadingID() - timestamp = now() - date = datetime.now() - data = { - 'client' : self.client, - 'action_type' : 'ma-type:log-message', - 'author' : 'fbid:' + str(self.uid), - 'thread_id' : '', - 'author_email' : '', - 'coordinates' : '', - 'timestamp' : timestamp, - 'timestamp_absolute' : 'Today', - 'timestamp_relative' : str(date.hour) + ":" + str(date.minute).zfill(2), - 'timestamp_time_passed' : '0', - 'is_unread' : False, - 'is_cleared' : False, - 'is_forward' : False, - 'is_filtered_content' : False, - 'is_spoof_warning' : False, - 'source' : 'source:chat:web', - 'source_tags[0]' : 'source:chat', - 'status' : '0', - 'offline_threading_id' : messageAndOTID, - 'message_id' : messageAndOTID, - 'threading_id': generateMessageID(self.client_id), - 'manual_retry_cnt' : '0', - 'thread_fbid' : threadID, - 'log_message_data[name]' : newTitle, - 'log_message_type' : 'log:thread-name' - } - - r = self._post(SendURL, data) - - return r.ok diff --git a/fbchat/models.py b/fbchat/models.py index 6c526a4..efebaf8 100644 --- a/fbchat/models.py +++ b/fbchat/models.py @@ -76,11 +76,11 @@ class ThreadType(Enum): class TypingStatus(Enum): - Deleted = 0 - Typing = 1 + DELETED = 0 + TYPING = 1 -class Sticker(Enum): +class EmojiSize(Enum): LARGE = '369239383222810' MEDIUM = '369239343222814' SMALL = '369239263222822' From 5da3e5e4bf02ba9bdbe699ffc28123a7359e8b7e Mon Sep 17 00:00:00 2001 From: Dainius Date: Tue, 9 May 2017 21:27:32 +0300 Subject: [PATCH 2/2] update tests --- fbchat/client.py | 59 ++++++++++--------- test_data.js | 6 ++ tests.py | 145 ++++++++++++++++++++++++++--------------------- 3 files changed, 117 insertions(+), 93 deletions(-) create mode 100644 test_data.js diff --git a/fbchat/client.py b/fbchat/client.py index c21cea0..442c8b7 100644 --- a/fbchat/client.py +++ b/fbchat/client.py @@ -199,7 +199,7 @@ class Client(object): self.payloadDefault = {} self.client_id = hex(int(random()*2147483648))[2:] self.start_time = now() - self.uid = int(self._session.cookies['c_user']) + self.uid = str(self._session.cookies['c_user']) self.user_channel = "p_" + str(self.uid) self.ttstamp = '' @@ -585,18 +585,18 @@ class Client(object): return self._send(thread_id, message, thread_type, None, image_id, None, None) # Doesn't upload properly - # def sendLocalImage(self, image_path: str, message: str = None, thread_id: str = None, thread_type: ThreadType = None): - # """ - # Sends an image from given URL to given (or default, if not) thread. - # :param image_path: path of an image to upload and send - # :param message: additional message - # :param thread_id: user/group chat ID - # :param thread_type: specify whether thread_id is user or group chat - # :return: a list of message ids of the sent message(s) - # """ - # mimetype = guess_type(image_path)[0] - # image_id = self._uploadImage({'file': (image_path, open(image_path, 'rb'), mimetype)}) - # return self._send(thread_id, message, thread_type, None, image_id, None, None) + def sendLocalImage(self, image_path: str, message: str = None, thread_id: str = None, thread_type: ThreadType = None): + """ + Sends an image from given URL to given (or default, if not) thread. + :param image_path: path of an image to upload and send + :param message: additional message + :param thread_id: user/group chat ID + :param thread_type: specify whether thread_id is user or group chat + :return: a list of message ids of the sent message(s) + """ + mimetype = guess_type(image_path)[0] + image_id = self._uploadImage({'file': (image_path, open(image_path, 'rb'), mimetype)}) + return self._send(thread_id, message, thread_type, None, image_id, None, None) def addUsersToChat(self, user_list: list, thread_id: str = None): """ @@ -659,28 +659,31 @@ class Client(object): # Strip the start and parse out the returned image_id return json.loads(response_content[9:])['payload']['metadata'][0]['image_id'] - def getThreadInfo(self, userID, last_n=20, start=None, is_user=True): + def getThreadInfo(self, last_n=20, thread_id: str = None, thread_type: ThreadType = None): """Get the info of one Thread - :param userID: ID of the user you want the messages from - :param last_n: (optional) number of retrieved messages from start - :param start: (optional) the start index of a thread (Deprecated) - :param is_user: (optional) determines if the userID is for user or thread + :param last_n: number of retrieved messages from start (default 20) + :param thread_id: user/group chat ID + :param thread_type: specify whether thread_id is user or group chat + :return: a list of messages """ + if thread_id is None and self.is_def_thread_set: + thread_id = self.def_thread_id + thread_type = self.def_thread_type + elif thread_id is None and not self.is_def_thread_set: + raise ValueError('Default Thread ID is not set.') + assert last_n > 0, 'length must be positive integer, got %d' % last_n - assert start is None, '`start` is deprecated, always 0 offset querry is returned' - if is_user: + + if thread_type == ThreadType.USER: key = 'user_ids' - else: + elif thread_type == ThreadType.GROUP: key = 'thread_fbids' - # deprecated - # `start` doesn't matter, always returns from the last - # data['messages[{}][{}][offset]'.format(key, userID)] = start - data = {'messages[{}][{}][offset]'.format(key, userID): 0, - 'messages[{}][{}][limit]'.format(key, userID): last_n - 1, - 'messages[{}][{}][timestamp]'.format(key, userID): now()} + data = {'messages[{}][{}][offset]'.format(key, thread_id): 0, + 'messages[{}][{}][limit]'.format(key, thread_id): last_n - 1, + 'messages[{}][{}][timestamp]'.format(key, thread_id): now()} r = self._post(MessagesURL, query=data) if not r.ok or len(r.text) == 0: @@ -691,7 +694,7 @@ class Client(object): return None messages = [] - for message in j['payload']['actions']: + for message in j['payload'].get('actions'): messages.append(Message(**message)) return list(reversed(messages)) diff --git a/test_data.js b/test_data.js new file mode 100644 index 0000000..f6d6250 --- /dev/null +++ b/test_data.js @@ -0,0 +1,6 @@ +{ + "email": "", + "password": "", + "user_thread_id": "", + "group_thread_id": "" +} \ No newline at end of file diff --git a/tests.py b/tests.py index 533e0d2..df26469 100644 --- a/tests.py +++ b/tests.py @@ -1,7 +1,10 @@ #!/usr/bin/env python +import time +import json import logging import fbchat +from fbchat.models import * import getpass import unittest import sys @@ -20,8 +23,8 @@ To use these tests, put: - email - password - a group_uid -- a user_uid (the user will be kicked from the group and then added again) -(seperated these by a newline) in a file called `tests.data`, or type them manually in the terminal prompts +- a user_uid (the user will be kicked from the group and then added again) `test_data.js`, +or type them manually in the terminal prompts Please remember to test both python v. 2.7 and python v. 3.6! @@ -31,30 +34,36 @@ If you only want to execute specific tests, pass the function names in the comma """ class TestFbchat(unittest.TestCase): - def test_login_functions(self): - self.assertTrue(client.is_logged_in()) - + def setUp(self): + pass + + def tearDown(self): + time.sleep(3) + + def test_loginFunctions(self): + self.assertTrue(client.isLoggedIn()) + client.logout() - - self.assertFalse(client.is_logged_in()) - + + self.assertFalse(client.isLoggedIn()) + with self.assertRaises(Exception): client.login("not@email.com", "not_password", max_retries=1) - + client.login(email, password) - - self.assertTrue(client.is_logged_in()) + + self.assertTrue(client.isLoggedIn()) def test_sessions(self): global client session_cookies = client.getSession() client = fbchat.Client(email, password, session_cookies=session_cookies) - - self.assertTrue(client.is_logged_in()) - def test_setDefaultRecipient(self): - client.setDefaultRecipient(client.uid, is_user=True) - self.assertTrue(client.send(message="test_default_recipient")) + self.assertTrue(client.isLoggedIn()) + + def test_setDefaultThreadId(self): + client.setDefaultThreadId(client.uid, ThreadType.USER) + self.assertTrue(client.sendMessage("test_default_recipient")) def test_getAllUsers(self): users = client.getAllUsers() @@ -63,9 +72,9 @@ class TestFbchat(unittest.TestCase): def test_getUsers(self): users = client.getUsers("Mark Zuckerberg") self.assertGreater(len(users), 0) - + u = users[0] - + # Test if values are set correctly self.assertIsInstance(u.uid, int) self.assertEquals(u.type, 'user') @@ -73,73 +82,80 @@ class TestFbchat(unittest.TestCase): self.assertEquals(u.url[:4], 'http') self.assertEquals(u.name, 'Mark Zuckerberg') self.assertGreater(u.score, 0) - - def test_send_likes(self): - self.assertTrue(client.send(client.uid, like='s')) - self.assertTrue(client.send(client.uid, like='m')) - self.assertTrue(client.send(client.uid, like='l')) - self.assertTrue(client.send(group_uid, like='s', is_user=False)) - self.assertTrue(client.send(group_uid, like='m', is_user=False)) - self.assertTrue(client.send(group_uid, like='l', is_user=False)) - - def test_send(self): - self.assertTrue(client.send(client.uid, message='test_send_user')) - self.assertTrue(client.send(group_uid, message='test_send_group', is_user=False)) - - def test_send_images(self): + + def test_sendEmoji(self): + self.assertTrue(client.sendEmoji(EmojiSize.SMALL, user_uid, ThreadType.USER)) + self.assertTrue(client.sendEmoji(EmojiSize.MEDIUM, user_uid, ThreadType.USER)) + self.assertTrue(client.sendEmoji(EmojiSize.LARGE, user_uid, ThreadType.USER)) + self.assertTrue(client.sendEmoji(EmojiSize.SMALL, group_uid, ThreadType.GROUP)) + self.assertTrue(client.sendEmoji(EmojiSize.MEDIUM, group_uid, ThreadType.GROUP)) + self.assertTrue(client.sendEmoji(EmojiSize.LARGE, group_uid, ThreadType.GROUP)) + + def test_sendMessage(self): + self.assertTrue(client.sendMessage('test_send_user', user_uid, ThreadType.USER)) + self.assertTrue(client.sendMessage('test_send_group', group_uid, ThreadType.GROUP)) + + def test_sendImages(self): image_url = 'https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-image-128.png' image_local_url = path.join(path.dirname(__file__), 'test_image.png') - self.assertTrue(client.sendRemoteImage(client.uid, message='test_send_user_images_remote', image=image_url)) - self.assertTrue(client.sendLocalImage(client.uid, message='test_send_user_images_local', image=image_local_url)) - self.assertTrue(client.sendRemoteImage(group_uid, message='test_send_group_images_remote', is_user=False, image=image_url)) - self.assertTrue(client.sendLocalImage(group_uid, message='test_send_group_images_local', is_user=False, image=image_local_url)) + self.assertTrue(client.sendRemoteImage(image_url, 'test_send_user_images_remote', user_uid, ThreadType.USER)) + self.assertTrue(client.sendRemoteImage(image_url, 'test_send_group_images_remote', group_uid, ThreadType.GROUP)) + # Idk why but doesnt work, payload is null + # self.assertTrue(client.sendLocalImage(image_local_url, 'test_send_group_images_local', user_uid, ThreadType.USER)) + # self.assertTrue(client.sendLocalImage(image_local_url, 'test_send_group_images_local', group_uid, ThreadType.GROUP)) def test_getThreadInfo(self): - info = client.getThreadInfo(client.uid, last_n=1) - self.assertEquals(info[0].author, 'fbid:' + str(client.uid)) - client.send(group_uid, message='test_getThreadInfo', is_user=False) - info = client.getThreadInfo(group_uid, last_n=1, is_user=False) - self.assertEquals(info[0].author, 'fbid:' + str(client.uid)) - self.assertEquals(info[0].body, 'test_getThreadInfo') + client.sendMessage('test_user_getThreadInfo', user_uid, ThreadType.USER) + time.sleep(3) + info = client.getThreadInfo(20, user_uid, ThreadType.USER) + self.assertEquals(info[0].author, 'fbid:' + client.uid) + self.assertEquals(info[0].body, 'test_user_getThreadInfo') - def test_markAs(self): - # To be implemented (requires some form of manual watching) - pass + client.sendMessage('test_group_getThreadInfo', group_uid, ThreadType.GROUP) + time.sleep(3) + info = client.getThreadInfo(20, group_uid, ThreadType.GROUP) + self.assertEquals(info[0].author, 'fbid:' + client.uid) + self.assertEquals(info[0].body, 'test_group_getThreadInfo') - def test_listen(self): - client.do_one_listen() + # def test_markAs(self): + # # To be implemented (requires some form of manual watching) + # pass + + # def test_listen(self): + # client.doOneListen() def test_getUserInfo(self): info = client.getUserInfo(4) self.assertEquals(info['name'], 'Mark Zuckerberg') - - def test_remove_add_from_chat(self): - self.assertTrue(client.remove_user_from_chat(group_uid, user_uid)) - self.assertTrue(client.add_users_to_chat(group_uid, user_uid)) - + + def test_removeAddFromChat(self): + self.assertTrue(client.removeUserFromChat(user_uid, group_uid)) + self.assertTrue(client.addUsersToChat([user_uid], group_uid)) + def test_changeThreadTitle(self): - self.assertTrue(client.changeThreadTitle(group_uid, 'test_changeThreadTitle')) + self.assertTrue(client.changeThreadTitle('test_changeThreadTitle', group_uid)) def start_test(param_client, param_group_uid, param_user_uid, tests=[]): global client global group_uid global user_uid - + client = param_client group_uid = param_group_uid user_uid = param_user_uid - + if len(tests) == 0: suite = unittest.TestLoader().loadTestsFromTestCase(TestFbchat) else: suite = unittest.TestSuite(map(TestFbchat, tests)) - print ('Starting test(s)') + print('Starting test(s)') unittest.TextTestRunner(verbosity=2).run(suite) +client = None -if __name__ == '__main__': +if __name__ == 'tests': # Python 3 does not use raw_input, whereas Python 2 does try: input = raw_input @@ -147,20 +163,19 @@ if __name__ == '__main__': pass try: - with open(path.join(path.dirname(__file__), 'tests.data'), 'r') as f: - content = f.readlines() - content = [x.strip() for x in content if len(x.strip()) != 0] - email = content[0] - password = content[1] - group_uid = content[2] - user_uid = content[3] + with open(path.join(path.dirname(__file__), 'test_data.js'), 'r') as f: + json = json.load(f) + email = json["email"] + password = json["password"] + user_uid = json["user_thread_id"] + group_uid = json["group_thread_id"] except (IOError, IndexError) as e: email = input('Email: ') password = getpass.getpass() group_uid = input('Please enter a group uid (To test group functionality): ') user_uid = input('Please enter a user uid (To test kicking/adding functionality): ') - print ('Logging in') + print('Logging in...') client = fbchat.Client(email, password) # Warning! Taking user input directly like this could be dangerous! Use only for testing purposes!