diff --git a/CHANGELOG.md b/CHANGELOG.md index 36321822..0b763cc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,6 +100,11 @@ manually if a timer is deleted. - Fix regex incorrectly being used on some messages +### Insights +#### Added +- `insights` Displays the insights for KoalaBot +- `servers ` Displays the servers that the bot is in with the given text in their name. (If left blank, displays all servers) + ## [0.2.0] - 15-10-2020 ### Text Filter ##### Added diff --git a/cogs/Insights.py b/cogs/Insights.py new file mode 100644 index 00000000..6f9d4e68 --- /dev/null +++ b/cogs/Insights.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python + +""" +Koala Bot Insights Code +Created by: Samuel Tiongson +""" +from discord.ext import commands + +import KoalaBot + + +class Insights(commands.Cog): + """ + A discord.py cog pertaining to showing the insights of the KoalaBot + """ + + def __init__(self, bot, database_manager=None): + self.bot = bot + + @commands.check(KoalaBot.is_owner) + @commands.command(name="insights", aliases=[]) + async def insights(self, ctx): + """ + Returns the number of servers KoalaBot is in and the total number of members of those servers. + + :param ctx: The discord context + """ + guilds = self.bot.guilds + number_of_servers = len(guilds) + number_of_members = 0 + + for guild in guilds: + number_of_members += guild.member_count + + await ctx.send(f"KoalaBot is in {number_of_servers} servers with a member total of {number_of_members}.") + + async def get_bot_guilds(self, arg=None): + # Retrieves AsyncIterator + guild_list = self.bot.fetch_guilds() + guild_list_names = [] + + # Cycle through iterator, check if there is an arg, if there is check against the arg, if not just append the + # guild name + async for guild in guild_list: + if arg is not None: + # Change arg and guild name to uppercase, and split guild name by spaces + if arg.upper() in guild.name.upper().split(" "): + guild_list_names.append(guild.name) + else: + guild_list_names.append(guild.name) + return guild_list_names + + @commands.check(KoalaBot.is_owner) + @commands.command(name="servers", aliases=[]) + async def servers(self, ctx, *, arg=None): + """ + Returns the names of the servers KoalaBot is in + + :param ctx: The discord context + :param arg: Searches for guilds with argument provided + """ + guild_list_names = await self.get_bot_guilds(arg) + + # If there are no guilds and no arguments + if len(guild_list_names) == 0 and arg is None: + await ctx.send("KoalaBot is in no servers!") + + # If there are no guilds but there are arguments + elif len(guild_list_names) == 0 and arg is not None: + await ctx.send(f"No servers with {arg} in their name!") + + # There must be guilds in the list + else: + string_to_send = '' + # While there are guilds in the list, run code + while len(guild_list_names) != 0: + # Get the length of the first server name + length = len(guild_list_names[0]) + # If this length + the current string length + 2 for comma and space is greater than 2000 + if len(string_to_send) + length + 2 > 2000: + # Print the string and reset it to nothing + await ctx.send(string_to_send) + string_to_send = '' + else: + # If the above is not true, then pop the server name from the list and add it to the string + guild = guild_list_names.pop(0) + string_to_send += guild + ", " + + # Remove the comma and space at the end of the string + await ctx.send(string_to_send[:-2]) + + +def setup(bot: KoalaBot) -> None: + """ + Load this cog to the KoalaBot. + :param bot: the bot client for KoalaBot + """ + bot.add_cog(Insights(bot)) + print("Insights is ready.") diff --git a/conftest.py b/conftest.py index 408db2a5..e7b5baa7 100644 --- a/conftest.py +++ b/conftest.py @@ -28,6 +28,20 @@ async def bot(event_loop): return b +@pytest.fixture(autouse=False) +async def bot_no_configure(event_loop): + """ + The bot conftest method but with no dpytest.configure() method call + """ + intents = discord.Intents.default() + intents.members = True + intents.guilds = True + intents.messages = True + b = commands.Bot(KoalaBot.COMMAND_PREFIX, loop=event_loop, intents=intents) + await dpytest.empty_queue() + return b + + @pytest.fixture(autouse=True) def setup_is_dpytest(): KoalaBot.is_dpytest = True diff --git a/tests/test_Insights.py b/tests/test_Insights.py new file mode 100644 index 00000000..96c9a846 --- /dev/null +++ b/tests/test_Insights.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python + +""" +Testing KoalaBot Insights Cog + +Commented using reStructuredText (reST) +""" +# Futures + +# Built-in/Generic Imports +import random + +# Libs +import discord.ext.test as dpytest +import pytest + +# Own modules +import KoalaBot +from cogs import Insights +from utils_testing import LastCtxCog + + +# Constants + +# Variables + +@pytest.fixture(scope="function", autouse=False) +def setup(bot): + utils_cog = LastCtxCog.LastCtxCog(bot) + insights_cog = Insights.Insights(bot) + bot.add_cog(utils_cog) + bot.add_cog(insights_cog) + print("Tests starting (setup)") + return bot + + +@pytest.fixture(scope="function", autouse=False) +def setup_no_conf(bot_no_configure): + bot = bot_no_configure + utils_cog = LastCtxCog.LastCtxCog(bot) + insights_cog = Insights.Insights(bot) + bot.add_cog(utils_cog) + bot.add_cog(insights_cog) + print("Tests starting (setup)") + return bot + + +@pytest.mark.asyncio +@pytest.mark.parametrize("num_guilds, num_members", + [(1, 1), (1, 2), (1, 10), (2, 2), (2, 5), (2, 20), (5, 100), (100, 10000), (20, 20000)]) +async def test_insights(num_guilds, num_members, setup): + test_config = dpytest.get_config() + + for i in range(num_guilds): + g = dpytest.back.make_guild(f"TestGuild {i}") + if test_config.guilds[i] is None: + test_config.guilds[i] = g + else: + test_config.guilds.append(g) + + for i in range(1, num_members): + m = dpytest.back.make_user(f"TestUser {i}", random.randint(1, 9999)) + dpytest.back.make_member(m, random.choice(test_config.guilds)) + + expected_users = 0 + for g in test_config.guilds: + expected_users += g.member_count + + await dpytest.message(KoalaBot.COMMAND_PREFIX + "insights") + assert dpytest.verify().message().content( + f"KoalaBot is in {len(dpytest.get_config().guilds)} servers with a member total of {expected_users}.") + + +@pytest.mark.asyncio +@pytest.mark.parametrize("num_guilds", + [1, 2, 5, 10, 100, 200, 500, 1000, 2000, 5000, 10000]) +async def test_servers_no_args(num_guilds, setup_no_conf): + dpytest.configure(setup_no_conf, num_guilds, 1, 1) + test_config = dpytest.get_config() + + for i in range(num_guilds): + g = dpytest.back.make_guild(f"Test Guild {i}") + if test_config.guilds[i] is None or g.name in [gg.name for gg in test_config.guilds]: + test_config.guilds[i] = g + else: + test_config.guilds.append(g) + + strings_expected = [] + msg = '' + len_msg = 0 + guild_list_names = [g.name for g in test_config.guilds] + while len(guild_list_names) != 0: + length = len(guild_list_names[0]) + if len(msg) + length + 2 > 2000 or len_msg == 100: + strings_expected.append(msg) + msg = '' + len_msg = 0 + else: + guild = guild_list_names.pop(0) + msg += guild + ", " + len_msg += 1 + strings_expected.append(msg[:-2]) + await dpytest.message(KoalaBot.COMMAND_PREFIX + "servers") + while not dpytest.sent_queue.empty(): + x = (await dpytest.sent_queue.get()).content + assert x in strings_expected, print(f"content = {x}") + assert dpytest.verify().message().nothing() + + +@pytest.mark.asyncio +@pytest.mark.parametrize("num_guilds", + [1, 2, 5, 10, 100, 1000, 10000]) +async def test_servers_args(num_guilds, setup_no_conf): + dpytest.configure(setup_no_conf, num_guilds, 1, 1) + test_config = dpytest.get_config() + + for i in range(num_guilds): + g = dpytest.back.make_guild(f"Test Guild {i}") + if test_config.guilds[i] is None or g.name in [gg.name for gg in test_config.guilds]: + test_config.guilds[i] = g + else: + test_config.guilds.append(g) + + arg = '1' + print(f"arg={arg}") + + strings_expected = [] + msg = '' + len_msg = 0 + guild_list_names = [] + async for guild in test_config.client.fetch_guilds(): + if arg is not None: + if arg.upper() in guild.name.upper().split(" "): + guild_list_names.append(guild.name) + else: + guild_list_names.append(guild.name) + + if len(guild_list_names) == 0: + strings_expected = [f"No servers with {arg} in their name!"] + else: + while len(guild_list_names) != 0: + length = len(guild_list_names[0]) + if len(msg) + length + 2 > 2000 or len_msg == 100: + strings_expected.append(msg) + msg = '' + len_msg = 0 + else: + guild = guild_list_names.pop(0) + msg += guild + ", " + len_msg += 1 + strings_expected.append(msg[:-2]) + print(strings_expected) + await dpytest.message(KoalaBot.COMMAND_PREFIX + f"servers {arg}") + while not dpytest.sent_queue.empty(): + x = (await dpytest.sent_queue.get()).content + assert x in strings_expected, print(f"content = {x}") + assert dpytest.verify().message().nothing()