Removed deprecations and new event system, improved other things

Removed deprecations
Removed new event system
Added documentation for all events
Added FAQ
Changed Client.uid to Client.id
Improved User model
Prepared for support of pages
This commit is contained in:
Mads Marquart
2017-06-20 14:57:23 +02:00
parent 0885796fa8
commit c81d7d2bfb
15 changed files with 768 additions and 700 deletions

View File

@@ -16,15 +16,9 @@ Client
This is the main class of `fbchat`, which contains all the methods you use to interract with Facebook.
You can extend this class, and overwrite the events, to provide custom event handling (mainly used while listening)
.. todo::
Add documentation for all events
.. autoclass:: Client(email, password, user_agent=None, max_retries=5, session_cookies=None, logging_level=logging.INFO)
.. autoclass:: Client(email, password, user_agent=None, max_tries=5, session_cookies=None, logging_level=logging.INFO)
:members:
.. automethod:: sendRemoteImage(image_url, message=None, thread_id=None, thread_type=ThreadType.USER)
.. automethod:: sendLocalImage(image_path, message=None, thread_id=None, thread_type=ThreadType.USER)
.. _api_models:

View File

@@ -7,6 +7,14 @@ Examples
These are a few examples on how to use `fbchat`. Remember to swap out `<email>` and `<password>` for your email and password
Basic example
-------------
This will show basic usage of `fbchat`
.. literalinclude:: ../examples/basic_usage.py
Interacting with Threads
------------------------

44
docs/faq.rst Normal file
View File

@@ -0,0 +1,44 @@
.. highlight:: python
.. module:: fbchat
.. _faq:
Frequently asked questions
==========================
Version X broke my installation
-------------------------------
We try to provide backwards compatability where possible, but since we're not part of Facebook,
most of the things may be broken at any point in time
Downgrade to an earlier version of fbchat, run this command
.. code-block:: sh
$ pip install fbchat==<X>
Where you replace ``<X>`` with the version you want to use
Will you be supporting creating posts/events/pages and so on?
-------------------------------------------------------------
We won't be focusing on anything else than chat-related things. This API is called `fbCHAT`, after all ;)
Submitting Issues
-----------------
If you're having trouble with some of the snippets, or you think some of the functionality is broken,
please feel free to submit an issue on `Github <https://github.com/carpedm20/fbchat>`_.
You should first login with ``logging_level`` set to ``logging.DEBUG``::
from fbchat import Client
import logging
client = Client('<email>', '<password>', logging_level=logging.DEBUG)
Then you can submit the relevant parts of this log, and detailed steps on how to reproduce
.. warning::
Always remove your credentials from any debug information you may provide us.
Preferably, use a test account, in case you miss anything

View File

@@ -36,6 +36,9 @@ Currently `fbchat` support Python 2.7, 3.4, 3.5 and 3.6:
This means doing the exact same GET/POST requests and tricking Facebook into thinking it's accessing the website normally.
Therefore, this API requires the credentials of a Facebook account.
.. note::
If you're having problems, please check the :ref:`faq`, before asking questions on Github
.. warning::
We are not responsible if your account gets banned for spammy activities,
such as sending lots of messages to people you don't know, sending messages very quickly,
@@ -60,3 +63,4 @@ Overview
testing
api
todo
faq

View File

@@ -53,9 +53,9 @@ These will specify whether the thread is a single user chat or a group chat.
This is required for many of `fbchat`'s functions, since Facebook differetiates between these two internally
Searching for group chats and finding their ID is not yet possible with `fbchat`,
but searching for users is possible via. :func:`Client.getUsers`. See :ref:`intro_fetching`
but searching for users is possible via. :func:`Client.searchForUsers`. See :ref:`intro_fetching`
You can get your own user ID by using :any:`Client.uid`
You can get your own user ID by using :any:`Client.id`
Getting the ID of a group chat is fairly trivial though, since you only need to navigate to `<https://www.facebook.com/messages/>`_,
click on the group you want to find the ID of, and then read the id from the address bar.
@@ -108,7 +108,7 @@ like adding users to and removing users from a group chat, logically only works
The simplest way of using `fbchat` is to send a message.
The following snippet will, as you've probably already figured out, send the message `test message` to your account::
message_id = client.sendMessage('test message', thread_id=client.uid, thread_type=ThreadType.USER)
message_id = client.sendMessage('test message', thread_id=client.id, thread_type=ThreadType.USER)
You can see a full example showing all the possible thread interactions with `fbchat` by going to :ref:`examples`
@@ -120,12 +120,12 @@ Fetching Information
You can use `fbchat` to fetch basic information like user names, profile pictures, thread names and user IDs
You can retrieve a user's ID with :func:`Client.getUsers`.
You can retrieve a user's ID with :func:`Client.searchForUsers`.
The following snippet will search for users by their name, take the first (and most likely) user, and then get their user ID from the result::
users = client.getUsers('<name of user>')
users = client.searchForUsers('<name of user>')
user = users[0]
print("User's ID: {}".format(user.uid))
print("User's ID: {}".format(user.id))
print("User's name: {}".format(user.name))
print("User's profile picture url: {}".format(user.photo))
print("User's main url: {}".format(user.url))
@@ -198,23 +198,3 @@ and ``mid``, ``ts``, ``metadata`` and ``msg`` got removed, but the function stil
the API actually requires that you include ``**kwargs`` as your final argument.
View the :ref:`examples` to see some more examples illustrating the event system
.. _intro_submitting:
Submitting Issues
-----------------
If you're having trouble with some of the snippets shown here, or you think some of the functionality is broken,
please feel free to submit an issue on `Github <https://github.com/carpedm20/fbchat>`_.
One side note is that you should first login with ``logging_level`` set to ``logging.DEBUG``::
from fbchat import Client
import logging
client = Client('<email>', '<password>', logging_level=logging.DEBUG)
Then you can submit the relevant parts of this log, and detailed steps on how to reproduce
.. warning::
Always remove your credentials from any debug information you may provide us.
Preferably, use a test account, in case you miss anything

View File

@@ -17,7 +17,7 @@ Missing Functionality
- This will use the graphql request API
- Implement chatting with pages
- This might require a new :class:`models.ThreadType`, something like ``ThreadType.PAGE``
- Rework `User`, `Thread` and `Message` models, and rework fething methods, to make the whole process more streamlined
- Rework `Message` model, to make the whole process more streamlined
Documentation

12
examples/basic_usage.py Normal file
View File

@@ -0,0 +1,12 @@
# -*- coding: UTF-8 -*-
from fbchat import Client
from fbchat.models import *
client = Client('<email>', '<password>')
print('Own id: {}'.format(client.id))
client.sendMessage('Hi me!', thread_id=self.id, thread_type=ThreadType.USER)
client.logout()

View File

@@ -3,42 +3,44 @@
from fbchat import Client
from fbchat.models import *
client = Client("<email>", "<password>")
client = Client('<email>', '<password>')
# Fetches a list of all users you're currently chatting with, as `User` objects
users = client.getAllUsers()
users = client.fetchAllUsers()
print('user IDs: {}'.format(user.uid for user in users))
print("user's names: {}".format(user.name for user in users))
print("users' IDs: {}".format(user.uid for user in users))
print("users' names: {}".format(user.name for user in users))
# If we have a user id, we can use `getUserInfo` to fetch a `User` object
user = client.getUserInfo('<user id>')
user = client.fetchUserInfo('<user id>')['<user id>']
# We can also query both mutiple users together, which returns list of `User` objects
users = client.getUserInfo('<1st user id>', '<2nd user id>', '<3rd user id>')
users = client.fetchUserInfo('<1st user id>', '<2nd user id>', '<3rd user id>')
print('User INFO: {}'.format(user))
print("User's INFO: {}".format(users))
print("user's name: {}".format(user.name))
print("users' names: {}".format(users[k].name for k in users))
# `getUsers` searches for the user and gives us a list of the results,
# `searchForUsers` searches for the user and gives us a list of the results,
# and then we just take the first one, aka. the most likely one:
user = client.getUsers('<name of user>')[0]
user = client.searchForUsers('<name of user>')[0]
print('user ID: {}'.format(user.uid))
print("user's name: {}".format(user.name))
print("user's photo: {}".format(user.photo))
print("Is user client's friend: {}".format(user.is_friend))
# Fetches a list of all threads you're currently chatting with
threads = client.getThreadList()
# Fetches a list of the 20 top threads you're currently chatting with
threads = client.fetchThreadList()
# Fetches the next 10 threads
threads += client.getThreadList(start=20, length=10)
threads += client.fetchThreadList(offset=20, amount=10)
print("Thread's INFO: {}".format(threads))
# Gets the last 10 messages sent to the thread
messages = client.getThreadInfo(last_n=10, thread_id='<thread id>', thread_type=ThreadType)
messages = client.fetchThreadMessages(offset=0, amount=10, thread_id='<thread id>', thread_type=ThreadType)
# Since the message come in reversed order, reverse them
messages.reverse()

View File

@@ -7,10 +7,11 @@ class RemoveBot(Client):
def onMessage(self, author_id, message, thread_id, thread_type, **kwargs):
# We can only kick people from group chats, so no need to try if it's a user chat
if message == 'Remove me!' and thread_type == ThreadType.GROUP:
log.info("{} will be removed from {}".format(author_id, thread_id))
log.info('{} will be removed from {}'.format(author_id, thread_id))
self.removeUserFromGroup(author_id, thread_id=thread_id)
else:
log.info("Message from {} in {} ({}): {}".format(author_id, thread_id, thread_type.name, message))
# Sends the data to the inherited onMessage, so that we can still see when a message is recieved
super(type(self), self).onMessage(author_id=author_id, message=message, thread_id=thread_id, thread_type=thread_type, **kwargs)
client = RemoveBot("<email>", "<password>")
client.listen()

View File

@@ -14,7 +14,7 @@ from datetime import datetime
from .client import *
__copyright__ = 'Copyright 2015 - {} by Taehoon Kim'.format(datetime.now().year)
__version__ = '0.10.4'
__version__ = '1.0.0'
__license__ = 'BSD'
__author__ = 'Taehoon Kim; Moreels Pieter-Jan; Mads Marquart'
__email__ = 'carpedm20@gmail.com'

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +0,0 @@
# -*- coding: UTF-8 -*-
class EventHook(object):
"""
A simple implementation of the Observer-Pattern.
All listeners added to this will be called, regardless of parameters
"""
def __init__(self, *args):
self._handlers = list(args)
def add(self, handler):
return self.__iadd__(handler)
def remove(self, handler):
return self.__isub__(handler)
def __iadd__(self, handler):
self._handlers.append(handler)
return self
def __isub__(self, handler):
self._handlers.remove(handler)
return self
def __call__(self, *args, **kwargs):
for handler in self._handlers:
handler(*args, **kwargs)

View File

@@ -3,81 +3,76 @@
from __future__ import unicode_literals
import enum
class User(object):
"""Represents a Facebook User"""
class Thread(object):
#: The unique identifier of the user. Can be used a `thread_id`. See :ref:`intro_threads` for more info
uid = None
#: Currently always set to `user`. Might change in the future
type = 'user'
#: The profile picture of the user
id = None
#: Specifies the type of thread. Uses ThreadType
type = None
#: The thread's picture
photo = None
#: The profile url
url = None
#: The name of the user
#: The name of the thread
name = None
#: Only used by :any:`Client.getUsers`. Each user is assigned a score between 0 and 1, based on how likely it is that they were the person being searched for
score = None
#: Dictionary containing raw userdata from when the :class:`User` was created
data = None
def __init__(self, data):
"""Represents a Facebook User"""
if data['type'] != 'user':
raise Exception("[!] %s <%s> is not a user" % (data['text'], data['path']))
self.uid = data['uid']
self.type = data['type']
self.photo = data['photo']
self.url = data['path']
self.name = data['text']
self.score = float(data['score'])
self.data = data
def __init__(self, _type, _id, photo=None, name=None):
"""Represents a Facebook thread"""
self.id = str(_id)
self.type = _type
self.photo = photo
self.name = name
def __repr__(self):
return self.__unicode__()
def __unicode__(self):
return u'<%s %s (%s)>' % (self.type.upper(), self.name, self.url)
return '<{} {} ({})>'.format(self.type.name, self.name, self.id)
@staticmethod
def _adaptFromChat(user_in_chat):
"""Adapts user info from chat to User model acceptable initial dict
:param user_in_chat: user info from chat
:return: :class:`User` object
class User(Thread):
#: The profile url
url = None
#: The users first name
first_name = None
#: The users last name
last_name = None
#: Whether the user and the client are friends
is_friend = None
#: The user's gender
gender = None
'dir': None,
'mThumbSrcSmall': None,
'is_friend': False,
'is_nonfriend_messenger_contact': True,
'alternateName': '',
'i18nGender': 16777216,
'vanity': '',
'type': 'friend',
'searchTokens': ['Voznesenskij', 'Sergej'],
'thumbSrc': 'https://fb-s-b-a.akamaihd.net/h-ak-xfa1/v/t1.0-1/c9.0.32.32/p32x32/10354686_10150004552801856_220367501106153455_n.jpg?oh=71a87d76d4e4d17615a20c43fb8dbb47&oe=59118CE4&__gda__=1493753268_ae75cef40e9785398e744259ccffd7ff',
'mThumbSrcLarge': None,
'firstName': 'Sergej',
'name': 'Sergej Voznesenskij',
'uri': 'https://www.facebook.com/profile.php?id=100014812758264',
'id': '100014812758264',
'gender': 2
"""
def __init__(self, _id, url=None, first_name=None, last_name=None, is_friend=None, gender=None, **kwargs):
"""Represents a Facebook user. Inherits `Thread`"""
super(User, self).__init__(ThreadType.USER, _id, **kwargs)
self.url = url
self.first_name = first_name
self.last_name = last_name
self.is_friend = is_friend
self.gender = gender
return {
'type': 'user',
'uid': user_in_chat['id'],
'photo': user_in_chat['thumbSrc'],
'path': user_in_chat['uri'],
'text': user_in_chat['name'],
'score': 1,
'data': user_in_chat,
}
class Thread(object):
"""Represents a thread. Currently just acts as a dict"""
def __init__(self, **entries):
self.__dict__.update(entries)
class Group(Thread):
def __init__(self, _id, **kwargs):
"""Represents a Facebook group. Inherits `Thread`"""
super(Group, self).__init__(ThreadType.GROUP, _id, **kwargs)
class Page(Thread):
#: The page's custom url
url = None
#: The name of the page's location city
city = None
#: Amount of likes the page has
likees = None
#: Some extra information about the page
sub_text = None
def __init__(self, _id, url=None, city=None, likees=None, sub_text=None, **kwargs):
"""Represents a Facebook page. Inherits `Thread`"""
super(Page, self).__init__(ThreadType.PAGE, _id, **kwargs)
self.url = url
self.city = city
self.likees = likees
self.sub_text = sub_text
class Message(object):
"""Represents a message. Currently just acts as a dict"""
@@ -94,6 +89,7 @@ class ThreadType(Enum):
"""Used to specify what type of Facebook thread is being used. See :ref:`intro_threads` for more info"""
USER = 1
GROUP = 2
PAGE = 3
class TypingStatus(Enum):
"""Used to specify whether the user is typing or has stopped typing"""

View File

@@ -6,8 +6,22 @@ import json
from time import time
from random import random
import warnings
import logging
from .models import *
# Python 2's `input` executes the input, whereas `raw_input` just returns the input
try:
input = raw_input
except NameError:
pass
# Log settings
log = logging.getLogger("client")
log.setLevel(logging.DEBUG)
# Creates the console handler
handler = logging.StreamHandler()
log.addHandler(handler)
#: Default list of user agents
USER_AGENTS = [
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36",
@@ -49,7 +63,7 @@ class ReqUrl(object):
STICKY = "https://0-edge-chat.facebook.com/pull"
PING = "https://0-channel-proxy-06-ash2.facebook.com/active_ping"
UPLOAD = "https://upload.facebook.com/ajax/mercury/upload.php"
USER_INFO = "https://www.facebook.com/chat/user_info/"
INFO = "https://www.facebook.com/chat/user_info/"
CONNECT = "https://www.facebook.com/ajax/add_friend/action.php?dpr=1"
REMOVE_USER = "https://www.facebook.com/chat/remove_participants/"
LOGOUT = "https://www.facebook.com/logout.php"
@@ -82,7 +96,7 @@ def get_decoded(r):
def get_json(r):
return json.loads(strip_to_json(get_decoded(r)))
def digit_to_char(digit):
def digitToChar(digit):
if digit < 10:
return str(digit)
return chr(ord('a') + digit - 10)
@@ -92,8 +106,8 @@ def str_base(number, base):
return '-' + str_base(-number, base)
(d, m) = divmod(number, base)
if d > 0:
return str_base(d, base) + digit_to_char(m)
return digit_to_char(m)
return str_base(d, base) + digitToChar(m)
return digitToChar(m)
def generateMessageID(client_id=None):
k = now()
@@ -110,31 +124,20 @@ def generateOfflineThreadingID():
msgs = format(ret, 'b') + string
return str(int(msgs, 2))
def isUserToThreadType(is_user):
return ThreadType.USER if is_user else ThreadType.GROUP
def checkRequest(r, check_json=True):
if not r.ok:
raise Exception('Error when sending request: Got {} response'.format(r.status_code))
def raise_exception(e):
raise e
content = get_decoded(r)
def deprecation(name, deprecated_in=None, removed_in=None, details='', stacklevel=3):
"""Used to mark parameters as deprecated. Will result in a warning being emmitted when the parameter is used."""
warning = "Client.{} is deprecated".format(name)
if deprecated_in:
warning += ' in v. {}'.format(deprecated_in)
if removed_in:
warning += ' and will be removed in v. {}'.format(removed_in)
if details:
warning += '. {}'.format(details)
if content is None or len(content) == 0:
raise Exception('Error when sending request: Got empty response')
warnings.simplefilter('always', DeprecationWarning)
warnings.warn(warning, category=DeprecationWarning, stacklevel=stacklevel)
warnings.simplefilter('default', DeprecationWarning)
def deprecated(deprecated_in=None, removed_in=None, details=''):
"""A decorator used to mark functions as deprecated. Will result in a warning being emmitted when the decorated function is used."""
def wrap(func, *args, **kwargs):
def wrapped_func(*args, **kwargs):
deprecation(func.__name__, deprecated_in=deprecated_in, removed_in=removed_in, details=details, stacklevel=3)
return func(*args, **kwargs)
return wrapped_func
return wrap
if check_json:
j = json.loads(strip_to_json(content))
if 'error' in j:
# 'errorDescription' is in the users own language!
raise Exception('Error #{} when sending request: {}'.format(j['error'], j['errorDescription']))
return j
else:
return r

136
tests.py
View File

@@ -27,7 +27,7 @@ class CustomClient(Client):
self.got_qprimer = False
super(type(self), self).__init__(*args, **kwargs)
def onQprimer(self, made, msg):
def onQprimer(self, msg, **kwargs):
self.got_qprimer = True
class TestFbchat(unittest.TestCase):
@@ -49,7 +49,7 @@ class TestFbchat(unittest.TestCase):
self.assertFalse(client.isLoggedIn())
with self.assertRaises(Exception):
client.login('<email>', '<password>', max_retries=1)
client.login('<email>', '<password>', max_tries=1)
client.login(email, password)
@@ -64,10 +64,10 @@ class TestFbchat(unittest.TestCase):
def test_defaultThread(self):
# setDefaultThread
client.setDefaultThread(group_uid, ThreadType.GROUP)
client.setDefaultThread(group_id, ThreadType.GROUP)
self.assertTrue(client.sendMessage('test_default_recipient★'))
client.setDefaultThread(user_uid, ThreadType.USER)
client.setDefaultThread(user_id, ThreadType.USER)
self.assertTrue(client.sendMessage('test_default_recipient★'))
# resetDefaultThread
@@ -75,57 +75,58 @@ class TestFbchat(unittest.TestCase):
with self.assertRaises(ValueError):
client.sendMessage('should_not_send')
def test_getAllUsers(self):
users = client.getAllUsers()
def test_fetchAllUsers(self):
users = client.fetchAllUsers()
self.assertGreater(len(users), 0)
def test_getUsers(self):
users = client.getUsers('Mark Zuckerberg')
def test_searchForUsers(self):
users = client.searchForUsers('Mark Zuckerberg')
self.assertGreater(len(users), 0)
u = users[0]
# Test if values are set correctly
self.assertIsInstance(u.uid, int)
self.assertEqual(u.type, 'user')
self.assertEqual(u.id, '4')
self.assertEqual(u.type, ThreadType.USER)
self.assertEqual(u.photo[:4], 'http')
self.assertEqual(u.url[:4], 'http')
self.assertEqual(u.name, 'Mark Zuckerberg')
self.assertGreater(u.score, 0)
def test_sendEmoji(self):
self.assertTrue(client.sendEmoji(size=EmojiSize.SMALL, thread_id=user_uid, thread_type=ThreadType.USER))
self.assertTrue(client.sendEmoji(size=EmojiSize.MEDIUM, thread_id=user_uid, thread_type=ThreadType.USER))
self.assertTrue(client.sendEmoji('😆', EmojiSize.LARGE, user_uid, ThreadType.USER))
self.assertIsNotNone(client.sendEmoji(size=EmojiSize.SMALL, thread_id=user_id, thread_type=ThreadType.USER))
self.assertIsNotNone(client.sendEmoji(size=EmojiSize.MEDIUM, thread_id=user_id, thread_type=ThreadType.USER))
self.assertIsNotNone(client.sendEmoji('😆', EmojiSize.LARGE, user_id, ThreadType.USER))
self.assertTrue(client.sendEmoji(size=EmojiSize.SMALL, thread_id=group_uid, thread_type=ThreadType.GROUP))
self.assertTrue(client.sendEmoji(size=EmojiSize.MEDIUM, thread_id=group_uid, thread_type=ThreadType.GROUP))
self.assertTrue(client.sendEmoji('😆', EmojiSize.LARGE, group_uid, ThreadType.GROUP))
self.assertIsNotNone(client.sendEmoji(size=EmojiSize.SMALL, thread_id=group_id, thread_type=ThreadType.GROUP))
self.assertIsNotNone(client.sendEmoji(size=EmojiSize.MEDIUM, thread_id=group_id, thread_type=ThreadType.GROUP))
self.assertIsNotNone(client.sendEmoji('😆', EmojiSize.LARGE, group_id, ThreadType.GROUP))
def test_sendMessage(self):
self.assertIsNotNone(client.sendMessage('test_send_user★', user_uid, ThreadType.USER))
self.assertIsNotNone(client.sendMessage('test_send_group★', group_uid, ThreadType.GROUP))
self.assertIsNone(client.sendMessage('test_send_user_should_fail★', user_uid, ThreadType.GROUP))
self.assertIsNone(client.sendMessage('test_send_group_should_fail★', group_uid, ThreadType.USER))
self.assertIsNotNone(client.sendMessage('test_send_user★', user_id, ThreadType.USER))
self.assertIsNotNone(client.sendMessage('test_send_group★', group_id, ThreadType.GROUP))
with self.assertRaises(Exception):
client.sendMessage('test_send_user_should_fail★', user_id, ThreadType.GROUP)
with self.assertRaises(Exception):
client.sendMessage('test_send_group_should_fail★', group_id, ThreadType.USER)
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__), 'tests/image.png')
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))
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))
self.assertTrue(client.sendRemoteImage(image_url, 'test_send_user_images_remote★', user_id, ThreadType.USER))
self.assertTrue(client.sendRemoteImage(image_url, 'test_send_group_images_remote★', group_id, ThreadType.GROUP))
self.assertTrue(client.sendLocalImage(image_local_url, 'test_send_group_images_local★', user_id, ThreadType.USER))
self.assertTrue(client.sendLocalImage(image_local_url, 'test_send_group_images_local★', group_id, ThreadType.GROUP))
def test_getThreadInfo(self):
client.sendMessage('test_user_getThreadInfo★', user_uid, ThreadType.USER)
def test_fetchThreadMessages(self):
client.sendMessage('test_user_getThreadInfo★', thread_id=user_id, thread_type=ThreadType.USER)
info = client.getThreadInfo(20, user_uid, ThreadType.USER)
info = client.fetchThreadMessages(offset=0, amount=2, thread_id=user_id, thread_type=ThreadType.USER)
self.assertEqual(info[0].author, 'fbid:' + client.uid)
self.assertEqual(info[0].body, 'test_user_getThreadInfo★')
client.sendMessage('test_group_getThreadInfo★', group_uid, ThreadType.GROUP)
client.sendMessage('test_group_getThreadInfo★', thread_id=group_id, thread_type=ThreadType.GROUP)
info = client.getThreadInfo(20, group_uid, ThreadType.GROUP)
info = client.fetchThreadMessages(offset=0, amount=2, thread_id=group_id, thread_type=ThreadType.GROUP)
self.assertEqual(info[0].author, 'fbid:' + client.uid)
self.assertEqual(info[0].body, 'test_group_getThreadInfo★')
@@ -136,58 +137,57 @@ class TestFbchat(unittest.TestCase):
self.assertTrue(client.got_qprimer)
def test_getUserInfo(self):
info = client.getUserInfo(4)
self.assertEqual(info['name'], 'Mark Zuckerberg')
def test_fetchUserInfo(self):
info = client.fetchUserInfo('4')['4']
self.assertEqual(info.name, 'Mark Zuckerberg')
def test_removeAddFromGroup(self):
self.assertTrue(client.removeUserFromGroup(user_uid, thread_id=group_uid))
self.assertTrue(client.addUsersToGroup(user_uid, thread_id=group_uid))
client.removeUserFromGroup(user_id, thread_id=group_id)
client.addUsersToGroup(user_id, thread_id=group_id)
def test_changeThreadTitle(self):
self.assertTrue(client.changeThreadTitle('test_changeThreadTitle★', thread_id=group_uid, thread_type=ThreadType.GROUP))
self.assertTrue(client.changeThreadTitle('test_changeThreadTitle★', thread_id=user_uid, thread_type=ThreadType.USER))
client.changeThreadTitle('test_changeThreadTitle★', thread_id=group_id, thread_type=ThreadType.GROUP)
client.changeThreadTitle('test_changeThreadTitle★', thread_id=user_id, thread_type=ThreadType.USER)
def test_changeNickname(self):
self.assertTrue(client.changeNickname('test_changeNicknameSelf★', client.uid, thread_id=user_uid, thread_type=ThreadType.USER))
self.assertTrue(client.changeNickname('test_changeNicknameOther★', user_uid, thread_id=user_uid, thread_type=ThreadType.USER))
self.assertTrue(client.changeNickname('test_changeNicknameSelf★', client.uid, thread_id=group_uid, thread_type=ThreadType.GROUP))
self.assertTrue(client.changeNickname('test_changeNicknameOther★', user_uid, thread_id=group_uid, thread_type=ThreadType.GROUP))
client.changeNickname('test_changeNicknameSelf★', client.id, thread_id=user_id, thread_type=ThreadType.USER)
client.changeNickname('test_changeNicknameOther★', user_id, thread_id=user_id, thread_type=ThreadType.USER)
client.changeNickname('test_changeNicknameSelf★', client.id, thread_id=group_id, thread_type=ThreadType.GROUP)
client.changeNickname('test_changeNicknameOther★', user_id, thread_id=group_id, thread_type=ThreadType.GROUP)
def test_changeThreadEmoji(self):
self.assertTrue(client.changeThreadEmoji('😀', group_uid))
self.assertTrue(client.changeThreadEmoji('😀', user_uid))
self.assertTrue(client.changeThreadEmoji('😆', group_uid))
self.assertTrue(client.changeThreadEmoji('😆', user_uid))
client.changeThreadEmoji('😀', group_id)
client.changeThreadEmoji('😀', user_id)
client.changeThreadEmoji('😆', group_id)
client.changeThreadEmoji('😆', user_id)
def test_changeThreadColor(self):
self.assertTrue(client.changeThreadColor(ThreadColor.BRILLIANT_ROSE, group_uid))
self.assertTrue(client.changeThreadColor(ThreadColor.MESSENGER_BLUE, group_uid))
self.assertTrue(client.changeThreadColor(ThreadColor.BRILLIANT_ROSE, user_uid))
self.assertTrue(client.changeThreadColor(ThreadColor.MESSENGER_BLUE, user_uid))
client.changeThreadColor(ThreadColor.BRILLIANT_ROSE, group_id)
client.changeThreadColor(ThreadColor.MESSENGER_BLUE, group_id)
client.changeThreadColor(ThreadColor.BRILLIANT_ROSE, user_id)
client.changeThreadColor(ThreadColor.MESSENGER_BLUE, user_id)
def test_reactToMessage(self):
mid = client.sendMessage('test_reactToMessage★', user_uid, ThreadType.USER)
self.assertTrue(client.reactToMessage(mid, MessageReaction.LOVE))
mid = client.sendMessage('test_reactToMessage★', group_uid, ThreadType.GROUP)
self.assertTrue(client.reactToMessage(mid, MessageReaction.LOVE))
mid = client.sendMessage('test_reactToMessage★', user_id, ThreadType.USER)
client.reactToMessage(mid, MessageReaction.LOVE)
mid = client.sendMessage('test_reactToMessage★', group_id, ThreadType.GROUP)
client.reactToMessage(mid, MessageReaction.LOVE)
def test_setTypingStatus(self):
self.assertTrue(client.sendMessage('Hi', thread_id=user_uid, thread_type=ThreadType.USER))
self.assertTrue(client.setTypingStatus(TypingStatus.TYPING, thread_id=user_uid, thread_type=ThreadType.USER))
self.assertTrue(client.setTypingStatus(TypingStatus.STOPPED, thread_id=user_uid, thread_type=ThreadType.USER))
self.assertTrue(client.setTypingStatus(TypingStatus.TYPING, thread_id=group_uid, thread_type=ThreadType.GROUP))
self.assertTrue(client.setTypingStatus(TypingStatus.STOPPED, thread_id=group_uid, thread_type=ThreadType.GROUP))
client.setTypingStatus(TypingStatus.TYPING, thread_id=user_id, thread_type=ThreadType.USER)
client.setTypingStatus(TypingStatus.STOPPED, thread_id=user_id, thread_type=ThreadType.USER)
client.setTypingStatus(TypingStatus.TYPING, thread_id=group_id, thread_type=ThreadType.GROUP)
client.setTypingStatus(TypingStatus.STOPPED, thread_id=group_id, thread_type=ThreadType.GROUP)
def start_test(param_client, param_group_uid, param_user_uid, tests=[]):
def start_test(param_client, param_group_id, param_user_id, tests=[]):
global client
global group_uid
global user_uid
global group_id
global user_id
client = param_client
group_uid = param_group_uid
user_uid = param_user_uid
group_id = param_group_id
user_id = param_user_id
tests = ['test_' + test if 'test_' != test[:5] else test for test in tests]
@@ -213,16 +213,16 @@ if __name__ == '__main__':
json = json.load(f)
email = json['email']
password = json['password']
user_uid = json['user_thread_id']
group_uid = json['group_thread_id']
user_id = json['user_thread_id']
group_id = json['group_thread_id']
except (IOError, IndexError) as e:
email = input('Email: ')
password = getpass()
group_uid = input('Please enter a group thread id (To test group functionality): ')
user_uid = input('Please enter a user thread id (To test kicking/adding functionality): ')
group_id = input('Please enter a group thread id (To test group functionality): ')
user_id = input('Please enter a user thread id (To test kicking/adding functionality): ')
print('Logging in...')
client = CustomClient(email, password, logging_level=logging_level)
# Warning! Taking user input directly like this could be dangerous! Use only for testing purposes!
start_test(client, group_uid, user_uid, argv[1:])
start_test(client, group_id, user_id, argv[1:])