From c047e30514c84b09d7075594eb0682dc3ad537bc Mon Sep 17 00:00:00 2001 From: romangraef Date: Sun, 19 Aug 2018 21:20:36 +0200 Subject: bulk ban api --- discord_ban_list/__init__.py | 2 ++ discord_ban_list/api.py | 25 +++++++++------ discord_ban_list/exceptions.py | 14 ++++++++ discord_ban_list/result.py | 12 +++++++ tests/test_login.py | 72 +++++++++++++++++++++++++++++++++++++++--- 5 files changed, 111 insertions(+), 14 deletions(-) create mode 100644 discord_ban_list/exceptions.py diff --git a/discord_ban_list/__init__.py b/discord_ban_list/__init__.py index a0fbd5c..98af9c6 100644 --- a/discord_ban_list/__init__.py +++ b/discord_ban_list/__init__.py @@ -3,6 +3,7 @@ Module for looking up entries/users on the bans.discord.id """ from .api import DiscordBanList +from .exceptions import TooManyUsers from .result import BanABC, NoBan, Ban from .version import VersionInfo, VERSION @@ -10,4 +11,5 @@ __all__ = ( 'VersionInfo', 'VERSION', 'DiscordBanList', 'BanABC', 'Ban', 'NoBan', + 'TooManyUsers', ) diff --git a/discord_ban_list/api.py b/discord_ban_list/api.py index 35e8c8a..25b46a2 100644 --- a/discord_ban_list/api.py +++ b/discord_ban_list/api.py @@ -3,11 +3,12 @@ Central API module. Most action taskes place here """ from asyncio import Lock -from typing import Union +from typing import Union, List from aiohttp import ClientSession -from .result import Ban, NoBan, BanABC +from .exceptions import TooManyUsers +from .result import BanABC CHECK_URL = 'https://bans.discord.id/api/check.php' @@ -36,17 +37,21 @@ class DiscordBanList(object): """ await self._guarantee_client() - async def check(self, user_id: Union[int, str]) -> BanABC: + async def check(self, *user_ids: Union[int, str]) -> List[BanABC]: """ - Check if a user is banned on DBans + Check if some users are banned on DBans - :param user_id: id of the user to be checked - :return: a :class:`BanABC` + :param user_ids: ids of the users to be checked + :return: a list of :class:`BanABC` """ - resp = await self._get('{base}?user_id={user_id}'.format(base=CHECK_URL, user_id=user_id)) - if resp['banned'] == "0": - return NoBan(user_id) - return Ban(user_id, resp['reason'], resp['case_id'], resp['proof']) + user_ids = list(set(user_ids)) + if len(user_ids) < 1: + return [] + if len(user_ids) > 99: + raise TooManyUsers(len(user_ids)) + resp = await self._get(CHECK_URL + '?' + '&'.join('user_id=' + + str(user_id) for user_id in user_ids)) + return [BanABC.parse(ban) for ban in resp] async def _get(self, url): async with self._client.get(url, diff --git a/discord_ban_list/exceptions.py b/discord_ban_list/exceptions.py new file mode 100644 index 0000000..c47e163 --- /dev/null +++ b/discord_ban_list/exceptions.py @@ -0,0 +1,14 @@ +""" +Module containing exceptions for the discord_ban_list module +""" + + +class TooManyUsers(Exception): + """ + Risen if more users than possible are requested. + + """ + + def __init__(self, count): + super(TooManyUsers, self).__init__( + "You may at most request 99 users at once. 99 < %s" % count) diff --git a/discord_ban_list/result.py b/discord_ban_list/result.py index 9d1a685..3d734c5 100644 --- a/discord_ban_list/result.py +++ b/discord_ban_list/result.py @@ -11,6 +11,18 @@ class BanABC(ABC): """ __slots__ = () + @staticmethod + def parse(obj: dict) -> 'BanABC': + """ + Parse a response from DBans into an apropiate :class:`BanABC` subclass object. + + :param obj: json response to be parsed + :return: the parsed ban + """ + if obj['banned'] == "0": + return NoBan(obj['user_id']) + return Ban(obj['user_id'], obj['reason'], obj['case_id'], obj['proof']) + @abstractproperty def user_id(self) -> int: """ diff --git a/tests/test_login.py b/tests/test_login.py index 79b1747..3c211dc 100644 --- a/tests/test_login.py +++ b/tests/test_login.py @@ -2,13 +2,13 @@ import os from asyncio import get_event_loop from unittest import TestCase -from discord_ban_list import DiscordBanList +from discord_ban_list import DiscordBanList, TooManyUsers async def a_test_valid_login(): ban_list = DiscordBanList(os.environ['token']) await ban_list.login() - ban = await ban_list.check(123) + ban = (await ban_list.check(123))[0] assert not ban.banned @@ -16,7 +16,7 @@ async def a_test_banned(): user = 123456789123456789 ban_list = DiscordBanList(os.environ['token']) await ban_list.login() - ban = await ban_list.check(user) + ban = (await ban_list.check(user))[0] assert ban.banned assert ban.user_id == user assert ban.case_id == 9999 @@ -24,9 +24,73 @@ async def a_test_banned(): assert ban.proof +async def a_test_multiple_bans(): + ban_list = DiscordBanList(os.environ['token']) + await ban_list.login() + bans = await ban_list.check( + 0, + 1, + 2, + 123456789123456789, + ) + for ban in bans: + if ban.user_id == 123456789123456789: + assert ban.banned + assert ban.case_id == 9999 + assert ban.proof + assert ban.reason + else: + assert not ban.banned + assert len(bans) == 4 + + +async def a_test_no_ids_provided(): + ban_list = DiscordBanList(os.environ['token']) + await ban_list.login() + bans = await ban_list.check() + assert bans == [] + + +async def a_test_id_de_duplication(): + ban_list = DiscordBanList(os.environ['token']) + await ban_list.login() + bans = await ban_list.check(*([123456789123456789] * 100 + [0] * 100)) + for ban in bans: + if ban.user_id == 123456789123456789: + assert ban.banned + assert ban.case_id == 9999 + assert ban.proof + assert ban.reason + else: + assert not ban.banned + assert len(bans) == 2 + + +async def a_test_too_many_ids_provided(): + ban_list = DiscordBanList(os.environ['token']) + await ban_list.login() + try: + await ban_list.check(*list(range(1000))) + except TooManyUsers: + return + assert False + + class TestSomething(TestCase): - def test_not_banned(self): + def test_valid_login(self): get_event_loop().run_until_complete(a_test_valid_login()) def test_banned(self): get_event_loop().run_until_complete(a_test_banned()) + + def test_multiple_bans(self): + get_event_loop().run_until_complete(a_test_multiple_bans()) + + def test_no_ids_provided(self): + get_event_loop().run_until_complete(a_test_no_ids_provided()) + + def test_id_de_duplication(self): + get_event_loop().run_until_complete(a_test_id_de_duplication()) + + def test_too_many_ids_provided(self): + get_event_loop().run_until_complete(a_test_too_many_ids_provided()) -- cgit