Skip to content

feat: insight cog #423

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ administrators
- Added optimisations for verified roles
- Add backend API
- Fix an issue where multiple emails can be passed to bypass domain-specific verification
### Insights
- Added new commands `insights` and `servers` under the insights cog

## [0.6.0] - 01-01-2023
- Upgraded to discord.py 2.1.0
Expand Down
3 changes: 2 additions & 1 deletion koala/cogs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from .announce import Announce
from .base import BaseCog
from .colour_role import ColourRole
from .insights import Insights
from .intro_cog import IntroCog
from .react_for_role import ReactForRole
from .text_filter import TextFilter
from .twitch_alert import TwitchAlert
from .verification import Verification
from .voting import Voting
from .voting import Voting
2 changes: 2 additions & 0 deletions koala/cogs/insights/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#from . import utils, db, models - use this if necessary in future
from .cog import Insights, setup
74 changes: 74 additions & 0 deletions koala/cogs/insights/cog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env python

"""
Koala Bot Insights Cog Code
"""
# Futures

# Built-in/Generic Imports

# Libs
from discord.ext import commands

# Own modules
import koalabot
from .log import logger
from .core import get_insights, get_servers

# Constants

# Variables


class Insights(commands.Cog, name="Insights"):
"""
A discord.py cog with commands to give insight into information about the servers the bot is in
"""

def __init__(self, bot):
self.bot = bot

@commands.command(name="insights")
@commands.check(koalabot.is_owner)
async def insights(self, ctx):
"""
Lists the number of servers the bot is in, and the total number of members across all of those servers
(includes double counting)
:param ctx: Context of the command
"""

await ctx.send(get_insights(self.bot))

@commands.command(name="servers")
@commands.check(koalabot.is_owner)
async def list_servers(self, ctx, filter_string=""):
"""
Lists all servers that the bot is in, packaged into 2000 character messages, optional parameter for specifying
that the servers must contain a specific string
:param ctx: Context of the command
:param filter_string: The string used to filter servers listed
"""

server_list = get_servers(self.bot, filter_string)

if len(server_list) > 0:
partial_message = server_list[0]
for guild in server_list[1:]:
guild_length = len(guild)
if len(partial_message) + guild_length + 2 > 2000:
await ctx.send(partial_message)
partial_message = guild
else:
partial_message += f", {guild}"
await ctx.send(partial_message)
else:
await ctx.send(f"No servers found containing the string \"{filter_string}\".")


async def setup(bot: koalabot) -> None:
"""
Loads this cog into the selected bot
:param bot: The client of the KoalaBot
"""
await bot.add_cog(Insights(bot))
logger.info("Insights Cog is ready.")
43 changes: 43 additions & 0 deletions koala/cogs/insights/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python

"""
Koala Bot Insights Core Code
"""
# Futures

# Built-in/Generic Imports

# Libs

# Own modules

# Constants

# Variables


def get_insights(bot):
"""
Processes the information concerning the number of servers and members, and the formatting for insights
:param bot: The bot for which information is being gathered
"""

message = f"Insights:\nThis bot is in a total of {len(bot.guilds)} servers.\nThere are a total " +\
f"of {sum([len(guild.members) for guild in bot.guilds])} members across these servers."

return message


def get_servers(bot, filter_string):
"""
Retrieves a list of servers that the bot is in, can also use a filter to select only servers containing that string
:param bot: The bot for which information is being gathered
:param filter_string: A filter string which allows only servers containing that string to be selected
"""

if filter_string != "":
server_list = [guild.name for guild in bot.guilds if filter_string.lower() in guild.name.lower()]
else:
server_list = [guild.name for guild in bot.guilds]

return server_list
3 changes: 3 additions & 0 deletions koala/cogs/insights/log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from koala.log import get_logger

logger = get_logger(__name__)
4 changes: 2 additions & 2 deletions koalabot.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
PERMISSION_ERROR_TEXT = "This guild does not have this extension enabled, go to http://koalabot.uk, " \
"or use `k!help enableExt` to enable it"
KOALA_IMAGE_URL = "https://cdn.discordapp.com/attachments/737280260541907015/752024535985029240/discord1.png"
ENABLED_COGS = ["base", "announce", "colour_role", "intro_cog", "react_for_role", "text_filter", "twitch_alert",
"verification", "voting"]
ENABLED_COGS = ["base", "announce", "colour_role", "insights", "intro_cog", "react_for_role", "text_filter",
"twitch_alert", "verification", "voting"]

# Variables
intent = discord.Intents.default()
Expand Down
Empty file added tests/cogs/insights/__init__.py
Empty file.
102 changes: 102 additions & 0 deletions tests/cogs/insights/test_cog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/env python
"""
Testing KoalaBot Insights Cog
"""
# Futures

# Built-in/Generic Imports

# Libs
import discord
import discord.ext.test as dpytest
import mock
import pytest
import pytest_asyncio

# Own modules
import koalabot
from koala.cogs.insights import cog

# Constants

# Variables


@pytest.mark.asyncio
async def test_setup(bot):
with mock.patch.object(discord.ext.commands.bot.Bot, 'add_cog') as mock1:
await cog.setup(bot)
mock1.assert_called()


@pytest_asyncio.fixture
async def insights_cog(bot: discord.ext.commands.Bot):
""" setup any state specific to the execution of the given module."""
insights_cog = cog.Insights(bot)
await bot.add_cog(insights_cog)
await dpytest.empty_queue()
dpytest.configure(bot)
return insights_cog


@pytest.mark.asyncio
@pytest.mark.parametrize("members,guilds", [(0, 0), (10, 10), (100, 100), (1000, 1000)])
async def test_insights(bot, insights_cog, members, guilds):
for x in range(members):
await dpytest.member_join(0, name=f"TestUser{x}", discrim={x})

for x in range(guilds):
guild = dpytest.backend.make_guild(name=f"FakeGuild{x}")
dpytest.get_config().guilds.append(guild)
await dpytest.member_join(guild, dpytest.get_config().client.user)

total_guilds = 1 + guilds
total_members = 2 + guilds + members

await dpytest.message(koalabot.COMMAND_PREFIX + "insights")

expected_message = f"Insights:\nThis bot is in a total of {total_guilds} servers." +\
f"\nThere are a total of {total_members} members across these servers."

assert dpytest.verify().message().content(expected_message)


@pytest.mark.asyncio
@pytest.mark.parametrize("total_servers", [0, 50, 500, 1000])
async def test_list_servers(bot, insights_cog, total_servers):
for x in range(total_servers):
guild = dpytest.backend.make_guild(name=f"{x}")
dpytest.get_config().guilds.append(guild)
await dpytest.member_join(guild, dpytest.get_config().client.user)

await dpytest.message(koalabot.COMMAND_PREFIX + "servers")

if total_servers > 0:
expected_partial_message = "Test Guild 0"
for x in range(total_servers):
int_length = len(str(x))
if len(expected_partial_message) + int_length + 2 > 2000:
assert dpytest.verify().message().content(expected_partial_message)
expected_partial_message = str(x)
else:
expected_partial_message += f", {x}"
assert dpytest.verify().message().content(expected_partial_message)
else:
assert dpytest.verify().message().content("Test Guild 0")


@pytest.mark.asyncio
@pytest.mark.parametrize("filter_term, expected", [("", "Test Guild 0, this, is, a, list, of, servers"),
("s", "Test Guild 0, this, is, list, servers"),
("is", "this, is, list"),
("hello", """No servers found containing the string "hello".""")])
async def test_list_servers_with_filter(bot, insights_cog, filter_term, expected):
server_list_names = ["this", "is", "a", "list", "of", "servers"]
for x in server_list_names:
guild = dpytest.backend.make_guild(name=x)
dpytest.get_config().guilds.append(guild)
await dpytest.member_join(guild, dpytest.get_config().client.user)

await dpytest.message(koalabot.COMMAND_PREFIX + "servers " + filter_term)

assert dpytest.verify().message().content(expected)