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:
@@ -16,15 +16,9 @@ Client
|
|||||||
This is the main class of `fbchat`, which contains all the methods you use to interract with Facebook.
|
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)
|
You can extend this class, and overwrite the events, to provide custom event handling (mainly used while listening)
|
||||||
|
|
||||||
.. todo::
|
.. autoclass:: Client(email, password, user_agent=None, max_tries=5, session_cookies=None, logging_level=logging.INFO)
|
||||||
Add documentation for all events
|
|
||||||
|
|
||||||
.. autoclass:: Client(email, password, user_agent=None, max_retries=5, session_cookies=None, logging_level=logging.INFO)
|
|
||||||
:members:
|
: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:
|
.. _api_models:
|
||||||
|
|
||||||
|
@@ -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
|
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
|
Interacting with Threads
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
44
docs/faq.rst
Normal file
44
docs/faq.rst
Normal 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
|
@@ -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.
|
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.
|
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::
|
.. warning::
|
||||||
We are not responsible if your account gets banned for spammy activities,
|
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,
|
such as sending lots of messages to people you don't know, sending messages very quickly,
|
||||||
@@ -60,3 +63,4 @@ Overview
|
|||||||
testing
|
testing
|
||||||
api
|
api
|
||||||
todo
|
todo
|
||||||
|
faq
|
||||||
|
@@ -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
|
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`,
|
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/>`_,
|
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.
|
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 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::
|
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`
|
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 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::
|
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]
|
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 name: {}".format(user.name))
|
||||||
print("User's profile picture url: {}".format(user.photo))
|
print("User's profile picture url: {}".format(user.photo))
|
||||||
print("User's main url: {}".format(user.url))
|
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.
|
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
|
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
|
|
||||||
|
@@ -17,7 +17,7 @@ Missing Functionality
|
|||||||
- This will use the graphql request API
|
- This will use the graphql request API
|
||||||
- Implement chatting with pages
|
- Implement chatting with pages
|
||||||
- This might require a new :class:`models.ThreadType`, something like ``ThreadType.PAGE``
|
- 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
|
Documentation
|
||||||
|
12
examples/basic_usage.py
Normal file
12
examples/basic_usage.py
Normal 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()
|
@@ -3,42 +3,44 @@
|
|||||||
from fbchat import Client
|
from fbchat import Client
|
||||||
from fbchat.models import *
|
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
|
# 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("users' IDs: {}".format(user.uid for user in users))
|
||||||
print("user's names: {}".format(user.name 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
|
# 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
|
# 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 name: {}".format(user.name))
|
||||||
print("User's INFO: {}".format(users))
|
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:
|
# 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 ID: {}'.format(user.uid))
|
||||||
print("user's name: {}".format(user.name))
|
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
|
# Fetches a list of the 20 top threads you're currently chatting with
|
||||||
threads = client.getThreadList()
|
threads = client.fetchThreadList()
|
||||||
# Fetches the next 10 threads
|
# 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))
|
print("Thread's INFO: {}".format(threads))
|
||||||
|
|
||||||
|
|
||||||
# Gets the last 10 messages sent to the thread
|
# 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
|
# Since the message come in reversed order, reverse them
|
||||||
messages.reverse()
|
messages.reverse()
|
||||||
|
|
||||||
|
@@ -7,10 +7,11 @@ class RemoveBot(Client):
|
|||||||
def onMessage(self, author_id, message, thread_id, thread_type, **kwargs):
|
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
|
# 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:
|
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)
|
self.removeUserFromGroup(author_id, thread_id=thread_id)
|
||||||
else:
|
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 = RemoveBot("<email>", "<password>")
|
||||||
client.listen()
|
client.listen()
|
||||||
|
@@ -14,7 +14,7 @@ from datetime import datetime
|
|||||||
from .client import *
|
from .client import *
|
||||||
|
|
||||||
__copyright__ = 'Copyright 2015 - {} by Taehoon Kim'.format(datetime.now().year)
|
__copyright__ = 'Copyright 2015 - {} by Taehoon Kim'.format(datetime.now().year)
|
||||||
__version__ = '0.10.4'
|
__version__ = '1.0.0'
|
||||||
__license__ = 'BSD'
|
__license__ = 'BSD'
|
||||||
__author__ = 'Taehoon Kim; Moreels Pieter-Jan; Mads Marquart'
|
__author__ = 'Taehoon Kim; Moreels Pieter-Jan; Mads Marquart'
|
||||||
__email__ = 'carpedm20@gmail.com'
|
__email__ = 'carpedm20@gmail.com'
|
||||||
|
972
fbchat/client.py
972
fbchat/client.py
File diff suppressed because it is too large
Load Diff
@@ -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)
|
|
118
fbchat/models.py
118
fbchat/models.py
@@ -3,81 +3,76 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
class User(object):
|
class Thread(object):
|
||||||
"""Represents a Facebook User"""
|
|
||||||
|
|
||||||
#: The unique identifier of the user. Can be used a `thread_id`. See :ref:`intro_threads` for more info
|
#: The unique identifier of the user. Can be used a `thread_id`. See :ref:`intro_threads` for more info
|
||||||
uid = None
|
id = None
|
||||||
#: Currently always set to `user`. Might change in the future
|
#: Specifies the type of thread. Uses ThreadType
|
||||||
type = 'user'
|
type = None
|
||||||
#: The profile picture of the user
|
#: The thread's picture
|
||||||
photo = None
|
photo = None
|
||||||
#: The profile url
|
#: The name of the thread
|
||||||
url = None
|
|
||||||
#: The name of the user
|
|
||||||
name = None
|
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):
|
def __init__(self, _type, _id, photo=None, name=None):
|
||||||
"""Represents a Facebook User"""
|
"""Represents a Facebook thread"""
|
||||||
if data['type'] != 'user':
|
self.id = str(_id)
|
||||||
raise Exception("[!] %s <%s> is not a user" % (data['text'], data['path']))
|
self.type = _type
|
||||||
self.uid = data['uid']
|
self.photo = photo
|
||||||
self.type = data['type']
|
self.name = name
|
||||||
self.photo = data['photo']
|
|
||||||
self.url = data['path']
|
|
||||||
self.name = data['text']
|
|
||||||
self.score = float(data['score'])
|
|
||||||
self.data = data
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return self.__unicode__()
|
return self.__unicode__()
|
||||||
|
|
||||||
def __unicode__(self):
|
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
|
class User(Thread):
|
||||||
:return: :class:`User` object
|
#: 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,
|
def __init__(self, _id, url=None, first_name=None, last_name=None, is_friend=None, gender=None, **kwargs):
|
||||||
'mThumbSrcSmall': None,
|
"""Represents a Facebook user. Inherits `Thread`"""
|
||||||
'is_friend': False,
|
super(User, self).__init__(ThreadType.USER, _id, **kwargs)
|
||||||
'is_nonfriend_messenger_contact': True,
|
self.url = url
|
||||||
'alternateName': '',
|
self.first_name = first_name
|
||||||
'i18nGender': 16777216,
|
self.last_name = last_name
|
||||||
'vanity': '',
|
self.is_friend = is_friend
|
||||||
'type': 'friend',
|
self.gender = gender
|
||||||
'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
|
|
||||||
"""
|
|
||||||
|
|
||||||
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):
|
class Group(Thread):
|
||||||
"""Represents a thread. Currently just acts as a dict"""
|
def __init__(self, _id, **kwargs):
|
||||||
def __init__(self, **entries):
|
"""Represents a Facebook group. Inherits `Thread`"""
|
||||||
self.__dict__.update(entries)
|
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):
|
class Message(object):
|
||||||
"""Represents a message. Currently just acts as a dict"""
|
"""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"""
|
"""Used to specify what type of Facebook thread is being used. See :ref:`intro_threads` for more info"""
|
||||||
USER = 1
|
USER = 1
|
||||||
GROUP = 2
|
GROUP = 2
|
||||||
|
PAGE = 3
|
||||||
|
|
||||||
class TypingStatus(Enum):
|
class TypingStatus(Enum):
|
||||||
"""Used to specify whether the user is typing or has stopped typing"""
|
"""Used to specify whether the user is typing or has stopped typing"""
|
||||||
|
@@ -6,8 +6,22 @@ import json
|
|||||||
from time import time
|
from time import time
|
||||||
from random import random
|
from random import random
|
||||||
import warnings
|
import warnings
|
||||||
|
import logging
|
||||||
from .models import *
|
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
|
#: Default list of user agents
|
||||||
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",
|
"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"
|
STICKY = "https://0-edge-chat.facebook.com/pull"
|
||||||
PING = "https://0-channel-proxy-06-ash2.facebook.com/active_ping"
|
PING = "https://0-channel-proxy-06-ash2.facebook.com/active_ping"
|
||||||
UPLOAD = "https://upload.facebook.com/ajax/mercury/upload.php"
|
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"
|
CONNECT = "https://www.facebook.com/ajax/add_friend/action.php?dpr=1"
|
||||||
REMOVE_USER = "https://www.facebook.com/chat/remove_participants/"
|
REMOVE_USER = "https://www.facebook.com/chat/remove_participants/"
|
||||||
LOGOUT = "https://www.facebook.com/logout.php"
|
LOGOUT = "https://www.facebook.com/logout.php"
|
||||||
@@ -82,7 +96,7 @@ def get_decoded(r):
|
|||||||
def get_json(r):
|
def get_json(r):
|
||||||
return json.loads(strip_to_json(get_decoded(r)))
|
return json.loads(strip_to_json(get_decoded(r)))
|
||||||
|
|
||||||
def digit_to_char(digit):
|
def digitToChar(digit):
|
||||||
if digit < 10:
|
if digit < 10:
|
||||||
return str(digit)
|
return str(digit)
|
||||||
return chr(ord('a') + digit - 10)
|
return chr(ord('a') + digit - 10)
|
||||||
@@ -92,8 +106,8 @@ def str_base(number, base):
|
|||||||
return '-' + str_base(-number, base)
|
return '-' + str_base(-number, base)
|
||||||
(d, m) = divmod(number, base)
|
(d, m) = divmod(number, base)
|
||||||
if d > 0:
|
if d > 0:
|
||||||
return str_base(d, base) + digit_to_char(m)
|
return str_base(d, base) + digitToChar(m)
|
||||||
return digit_to_char(m)
|
return digitToChar(m)
|
||||||
|
|
||||||
def generateMessageID(client_id=None):
|
def generateMessageID(client_id=None):
|
||||||
k = now()
|
k = now()
|
||||||
@@ -110,31 +124,20 @@ def generateOfflineThreadingID():
|
|||||||
msgs = format(ret, 'b') + string
|
msgs = format(ret, 'b') + string
|
||||||
return str(int(msgs, 2))
|
return str(int(msgs, 2))
|
||||||
|
|
||||||
def isUserToThreadType(is_user):
|
def checkRequest(r, check_json=True):
|
||||||
return ThreadType.USER if is_user else ThreadType.GROUP
|
if not r.ok:
|
||||||
|
raise Exception('Error when sending request: Got {} response'.format(r.status_code))
|
||||||
|
|
||||||
def raise_exception(e):
|
content = get_decoded(r)
|
||||||
raise e
|
|
||||||
|
|
||||||
def deprecation(name, deprecated_in=None, removed_in=None, details='', stacklevel=3):
|
if content is None or len(content) == 0:
|
||||||
"""Used to mark parameters as deprecated. Will result in a warning being emmitted when the parameter is used."""
|
raise Exception('Error when sending request: Got empty response')
|
||||||
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)
|
|
||||||
|
|
||||||
warnings.simplefilter('always', DeprecationWarning)
|
if check_json:
|
||||||
warnings.warn(warning, category=DeprecationWarning, stacklevel=stacklevel)
|
j = json.loads(strip_to_json(content))
|
||||||
warnings.simplefilter('default', DeprecationWarning)
|
if 'error' in j:
|
||||||
|
# 'errorDescription' is in the users own language!
|
||||||
def deprecated(deprecated_in=None, removed_in=None, details=''):
|
raise Exception('Error #{} when sending request: {}'.format(j['error'], j['errorDescription']))
|
||||||
"""A decorator used to mark functions as deprecated. Will result in a warning being emmitted when the decorated function is used."""
|
return j
|
||||||
def wrap(func, *args, **kwargs):
|
else:
|
||||||
def wrapped_func(*args, **kwargs):
|
return r
|
||||||
deprecation(func.__name__, deprecated_in=deprecated_in, removed_in=removed_in, details=details, stacklevel=3)
|
|
||||||
return func(*args, **kwargs)
|
|
||||||
return wrapped_func
|
|
||||||
return wrap
|
|
||||||
|
136
tests.py
136
tests.py
@@ -27,7 +27,7 @@ class CustomClient(Client):
|
|||||||
self.got_qprimer = False
|
self.got_qprimer = False
|
||||||
super(type(self), self).__init__(*args, **kwargs)
|
super(type(self), self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def onQprimer(self, made, msg):
|
def onQprimer(self, msg, **kwargs):
|
||||||
self.got_qprimer = True
|
self.got_qprimer = True
|
||||||
|
|
||||||
class TestFbchat(unittest.TestCase):
|
class TestFbchat(unittest.TestCase):
|
||||||
@@ -49,7 +49,7 @@ class TestFbchat(unittest.TestCase):
|
|||||||
self.assertFalse(client.isLoggedIn())
|
self.assertFalse(client.isLoggedIn())
|
||||||
|
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
client.login('<email>', '<password>', max_retries=1)
|
client.login('<email>', '<password>', max_tries=1)
|
||||||
|
|
||||||
client.login(email, password)
|
client.login(email, password)
|
||||||
|
|
||||||
@@ -64,10 +64,10 @@ class TestFbchat(unittest.TestCase):
|
|||||||
|
|
||||||
def test_defaultThread(self):
|
def test_defaultThread(self):
|
||||||
# setDefaultThread
|
# setDefaultThread
|
||||||
client.setDefaultThread(group_uid, ThreadType.GROUP)
|
client.setDefaultThread(group_id, ThreadType.GROUP)
|
||||||
self.assertTrue(client.sendMessage('test_default_recipient★'))
|
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★'))
|
self.assertTrue(client.sendMessage('test_default_recipient★'))
|
||||||
|
|
||||||
# resetDefaultThread
|
# resetDefaultThread
|
||||||
@@ -75,57 +75,58 @@ class TestFbchat(unittest.TestCase):
|
|||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
client.sendMessage('should_not_send')
|
client.sendMessage('should_not_send')
|
||||||
|
|
||||||
def test_getAllUsers(self):
|
def test_fetchAllUsers(self):
|
||||||
users = client.getAllUsers()
|
users = client.fetchAllUsers()
|
||||||
self.assertGreater(len(users), 0)
|
self.assertGreater(len(users), 0)
|
||||||
|
|
||||||
def test_getUsers(self):
|
def test_searchForUsers(self):
|
||||||
users = client.getUsers('Mark Zuckerberg')
|
users = client.searchForUsers('Mark Zuckerberg')
|
||||||
self.assertGreater(len(users), 0)
|
self.assertGreater(len(users), 0)
|
||||||
|
|
||||||
u = users[0]
|
u = users[0]
|
||||||
|
|
||||||
# Test if values are set correctly
|
# Test if values are set correctly
|
||||||
self.assertIsInstance(u.uid, int)
|
self.assertEqual(u.id, '4')
|
||||||
self.assertEqual(u.type, 'user')
|
self.assertEqual(u.type, ThreadType.USER)
|
||||||
self.assertEqual(u.photo[:4], 'http')
|
self.assertEqual(u.photo[:4], 'http')
|
||||||
self.assertEqual(u.url[:4], 'http')
|
self.assertEqual(u.url[:4], 'http')
|
||||||
self.assertEqual(u.name, 'Mark Zuckerberg')
|
self.assertEqual(u.name, 'Mark Zuckerberg')
|
||||||
self.assertGreater(u.score, 0)
|
|
||||||
|
|
||||||
def test_sendEmoji(self):
|
def test_sendEmoji(self):
|
||||||
self.assertTrue(client.sendEmoji(size=EmojiSize.SMALL, thread_id=user_uid, thread_type=ThreadType.USER))
|
self.assertIsNotNone(client.sendEmoji(size=EmojiSize.SMALL, thread_id=user_id, thread_type=ThreadType.USER))
|
||||||
self.assertTrue(client.sendEmoji(size=EmojiSize.MEDIUM, thread_id=user_uid, thread_type=ThreadType.USER))
|
self.assertIsNotNone(client.sendEmoji(size=EmojiSize.MEDIUM, thread_id=user_id, thread_type=ThreadType.USER))
|
||||||
self.assertTrue(client.sendEmoji('😆', EmojiSize.LARGE, user_uid, 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.assertIsNotNone(client.sendEmoji(size=EmojiSize.SMALL, thread_id=group_id, thread_type=ThreadType.GROUP))
|
||||||
self.assertTrue(client.sendEmoji(size=EmojiSize.MEDIUM, thread_id=group_uid, thread_type=ThreadType.GROUP))
|
self.assertIsNotNone(client.sendEmoji(size=EmojiSize.MEDIUM, thread_id=group_id, thread_type=ThreadType.GROUP))
|
||||||
self.assertTrue(client.sendEmoji('😆', EmojiSize.LARGE, group_uid, ThreadType.GROUP))
|
self.assertIsNotNone(client.sendEmoji('😆', EmojiSize.LARGE, group_id, ThreadType.GROUP))
|
||||||
|
|
||||||
def test_sendMessage(self):
|
def test_sendMessage(self):
|
||||||
self.assertIsNotNone(client.sendMessage('test_send_user★', user_uid, ThreadType.USER))
|
self.assertIsNotNone(client.sendMessage('test_send_user★', user_id, ThreadType.USER))
|
||||||
self.assertIsNotNone(client.sendMessage('test_send_group★', group_uid, ThreadType.GROUP))
|
self.assertIsNotNone(client.sendMessage('test_send_group★', group_id, ThreadType.GROUP))
|
||||||
self.assertIsNone(client.sendMessage('test_send_user_should_fail★', user_uid, ThreadType.GROUP))
|
with self.assertRaises(Exception):
|
||||||
self.assertIsNone(client.sendMessage('test_send_group_should_fail★', group_uid, ThreadType.USER))
|
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):
|
def test_sendImages(self):
|
||||||
image_url = 'https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-image-128.png'
|
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')
|
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_user_images_remote★', user_id, ThreadType.USER))
|
||||||
self.assertTrue(client.sendRemoteImage(image_url, 'test_send_group_images_remote★', group_uid, ThreadType.GROUP))
|
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_uid, ThreadType.USER))
|
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_uid, ThreadType.GROUP))
|
self.assertTrue(client.sendLocalImage(image_local_url, 'test_send_group_images_local★', group_id, ThreadType.GROUP))
|
||||||
|
|
||||||
def test_getThreadInfo(self):
|
def test_fetchThreadMessages(self):
|
||||||
client.sendMessage('test_user_getThreadInfo★', user_uid, ThreadType.USER)
|
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].author, 'fbid:' + client.uid)
|
||||||
self.assertEqual(info[0].body, 'test_user_getThreadInfo★')
|
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].author, 'fbid:' + client.uid)
|
||||||
self.assertEqual(info[0].body, 'test_group_getThreadInfo★')
|
self.assertEqual(info[0].body, 'test_group_getThreadInfo★')
|
||||||
|
|
||||||
@@ -136,58 +137,57 @@ class TestFbchat(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertTrue(client.got_qprimer)
|
self.assertTrue(client.got_qprimer)
|
||||||
|
|
||||||
def test_getUserInfo(self):
|
def test_fetchUserInfo(self):
|
||||||
info = client.getUserInfo(4)
|
info = client.fetchUserInfo('4')['4']
|
||||||
self.assertEqual(info['name'], 'Mark Zuckerberg')
|
self.assertEqual(info.name, 'Mark Zuckerberg')
|
||||||
|
|
||||||
def test_removeAddFromGroup(self):
|
def test_removeAddFromGroup(self):
|
||||||
self.assertTrue(client.removeUserFromGroup(user_uid, thread_id=group_uid))
|
client.removeUserFromGroup(user_id, thread_id=group_id)
|
||||||
self.assertTrue(client.addUsersToGroup(user_uid, thread_id=group_uid))
|
client.addUsersToGroup(user_id, thread_id=group_id)
|
||||||
|
|
||||||
def test_changeThreadTitle(self):
|
def test_changeThreadTitle(self):
|
||||||
self.assertTrue(client.changeThreadTitle('test_changeThreadTitle★', thread_id=group_uid, thread_type=ThreadType.GROUP))
|
client.changeThreadTitle('test_changeThreadTitle★', thread_id=group_id, thread_type=ThreadType.GROUP)
|
||||||
self.assertTrue(client.changeThreadTitle('test_changeThreadTitle★', thread_id=user_uid, thread_type=ThreadType.USER))
|
client.changeThreadTitle('test_changeThreadTitle★', thread_id=user_id, thread_type=ThreadType.USER)
|
||||||
|
|
||||||
def test_changeNickname(self):
|
def test_changeNickname(self):
|
||||||
self.assertTrue(client.changeNickname('test_changeNicknameSelf★', client.uid, thread_id=user_uid, thread_type=ThreadType.USER))
|
client.changeNickname('test_changeNicknameSelf★', client.id, thread_id=user_id, thread_type=ThreadType.USER)
|
||||||
self.assertTrue(client.changeNickname('test_changeNicknameOther★', user_uid, thread_id=user_uid, thread_type=ThreadType.USER))
|
client.changeNickname('test_changeNicknameOther★', user_id, thread_id=user_id, thread_type=ThreadType.USER)
|
||||||
self.assertTrue(client.changeNickname('test_changeNicknameSelf★', client.uid, thread_id=group_uid, thread_type=ThreadType.GROUP))
|
client.changeNickname('test_changeNicknameSelf★', client.id, thread_id=group_id, thread_type=ThreadType.GROUP)
|
||||||
self.assertTrue(client.changeNickname('test_changeNicknameOther★', user_uid, thread_id=group_uid, thread_type=ThreadType.GROUP))
|
client.changeNickname('test_changeNicknameOther★', user_id, thread_id=group_id, thread_type=ThreadType.GROUP)
|
||||||
|
|
||||||
def test_changeThreadEmoji(self):
|
def test_changeThreadEmoji(self):
|
||||||
self.assertTrue(client.changeThreadEmoji('😀', group_uid))
|
client.changeThreadEmoji('😀', group_id)
|
||||||
self.assertTrue(client.changeThreadEmoji('😀', user_uid))
|
client.changeThreadEmoji('😀', user_id)
|
||||||
self.assertTrue(client.changeThreadEmoji('😆', group_uid))
|
client.changeThreadEmoji('😆', group_id)
|
||||||
self.assertTrue(client.changeThreadEmoji('😆', user_uid))
|
client.changeThreadEmoji('😆', user_id)
|
||||||
|
|
||||||
def test_changeThreadColor(self):
|
def test_changeThreadColor(self):
|
||||||
self.assertTrue(client.changeThreadColor(ThreadColor.BRILLIANT_ROSE, group_uid))
|
client.changeThreadColor(ThreadColor.BRILLIANT_ROSE, group_id)
|
||||||
self.assertTrue(client.changeThreadColor(ThreadColor.MESSENGER_BLUE, group_uid))
|
client.changeThreadColor(ThreadColor.MESSENGER_BLUE, group_id)
|
||||||
self.assertTrue(client.changeThreadColor(ThreadColor.BRILLIANT_ROSE, user_uid))
|
client.changeThreadColor(ThreadColor.BRILLIANT_ROSE, user_id)
|
||||||
self.assertTrue(client.changeThreadColor(ThreadColor.MESSENGER_BLUE, user_uid))
|
client.changeThreadColor(ThreadColor.MESSENGER_BLUE, user_id)
|
||||||
|
|
||||||
def test_reactToMessage(self):
|
def test_reactToMessage(self):
|
||||||
mid = client.sendMessage('test_reactToMessage★', user_uid, ThreadType.USER)
|
mid = client.sendMessage('test_reactToMessage★', user_id, ThreadType.USER)
|
||||||
self.assertTrue(client.reactToMessage(mid, MessageReaction.LOVE))
|
client.reactToMessage(mid, MessageReaction.LOVE)
|
||||||
mid = client.sendMessage('test_reactToMessage★', group_uid, ThreadType.GROUP)
|
mid = client.sendMessage('test_reactToMessage★', group_id, ThreadType.GROUP)
|
||||||
self.assertTrue(client.reactToMessage(mid, MessageReaction.LOVE))
|
client.reactToMessage(mid, MessageReaction.LOVE)
|
||||||
|
|
||||||
def test_setTypingStatus(self):
|
def test_setTypingStatus(self):
|
||||||
self.assertTrue(client.sendMessage('Hi', thread_id=user_uid, thread_type=ThreadType.USER))
|
client.setTypingStatus(TypingStatus.TYPING, thread_id=user_id, thread_type=ThreadType.USER)
|
||||||
self.assertTrue(client.setTypingStatus(TypingStatus.TYPING, thread_id=user_uid, thread_type=ThreadType.USER))
|
client.setTypingStatus(TypingStatus.STOPPED, thread_id=user_id, thread_type=ThreadType.USER)
|
||||||
self.assertTrue(client.setTypingStatus(TypingStatus.STOPPED, thread_id=user_uid, thread_type=ThreadType.USER))
|
client.setTypingStatus(TypingStatus.TYPING, thread_id=group_id, thread_type=ThreadType.GROUP)
|
||||||
self.assertTrue(client.setTypingStatus(TypingStatus.TYPING, thread_id=group_uid, thread_type=ThreadType.GROUP))
|
client.setTypingStatus(TypingStatus.STOPPED, thread_id=group_id, thread_type=ThreadType.GROUP)
|
||||||
self.assertTrue(client.setTypingStatus(TypingStatus.STOPPED, thread_id=group_uid, 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 client
|
||||||
global group_uid
|
global group_id
|
||||||
global user_uid
|
global user_id
|
||||||
|
|
||||||
client = param_client
|
client = param_client
|
||||||
group_uid = param_group_uid
|
group_id = param_group_id
|
||||||
user_uid = param_user_uid
|
user_id = param_user_id
|
||||||
|
|
||||||
tests = ['test_' + test if 'test_' != test[:5] else test for test in tests]
|
tests = ['test_' + test if 'test_' != test[:5] else test for test in tests]
|
||||||
|
|
||||||
@@ -213,16 +213,16 @@ if __name__ == '__main__':
|
|||||||
json = json.load(f)
|
json = json.load(f)
|
||||||
email = json['email']
|
email = json['email']
|
||||||
password = json['password']
|
password = json['password']
|
||||||
user_uid = json['user_thread_id']
|
user_id = json['user_thread_id']
|
||||||
group_uid = json['group_thread_id']
|
group_id = json['group_thread_id']
|
||||||
except (IOError, IndexError) as e:
|
except (IOError, IndexError) as e:
|
||||||
email = input('Email: ')
|
email = input('Email: ')
|
||||||
password = getpass()
|
password = getpass()
|
||||||
group_uid = input('Please enter a group thread id (To test group functionality): ')
|
group_id = 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): ')
|
user_id = input('Please enter a user thread id (To test kicking/adding functionality): ')
|
||||||
|
|
||||||
print('Logging in...')
|
print('Logging in...')
|
||||||
client = CustomClient(email, password, logging_level=logging_level)
|
client = CustomClient(email, password, logging_level=logging_level)
|
||||||
|
|
||||||
# Warning! Taking user input directly like this could be dangerous! Use only for testing purposes!
|
# 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:])
|
||||||
|
Reference in New Issue
Block a user