diff --git a/KoalaBot.py b/KoalaBot.py index bdb1171d..5d54407e 100644 --- a/KoalaBot.py +++ b/KoalaBot.py @@ -22,11 +22,14 @@ # Built-in/Generic Imports import os import logging +from typing import Counter # Libs import discord -from discord.ext import commands +import DiscordUtils +from discord.ext import commands, menus from dotenv import load_dotenv +from collections import OrderedDict, deque, Counter # Own modules from utils.KoalaDBManager import KoalaDBManager as DBManager @@ -49,6 +52,20 @@ 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" + +# Help Command configuration +attributes = { + 'name': "help", + 'aliases': ["HELP", "helps", "HELPS", "hell", "HELL", "h", "H", "command", "COMMAND", "commands", "COMMANDS", "how", "HOW", "com", "COM", "c", "C", "Koala", "kola", "KOALA"], + 'cooldown': commands.Cooldown(1, 5.0, commands.BucketType.user) # Lets users run the help command once every 5 seconds to reduce spam +} +# During declaration +# help_object = commands.HelpCommand(command_attrs = attributes) # Needs the following to be added to the COMMAND_PREFIX sections: help_command = help_object + +# OR through attribute assignment +help_object = commands.MinimalHelpCommand() # HelpCommand +help_object.command_attrs = attributes + # Variables started = False if discord.__version__ != "1.3.4": @@ -57,16 +74,63 @@ intent.members = True intent.guilds = True intent.messages = True - client = commands.Bot(command_prefix=COMMAND_PREFIX, intents=intent) + client = commands.Bot(command_prefix = COMMAND_PREFIX, intents=intent, help_command=help_object) else: logging.info("discord.py v1.3.4: Intents Disabled") - client = commands.Bot(command_prefix=COMMAND_PREFIX) + client = commands.Bot(command_prefix=COMMAND_PREFIX, help_command = help_object) database_manager = DBManager(DATABASE_PATH, DB_KEY) logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)-8s %(message)s') logger = logging.getLogger('discord') is_dpytest = False +class HelpCom(commands.MinimalHelpCommand): # HelpCommand + def get_command_signature(self, command): + """Method to return a commands name and signature""" + return '%s%s %s' % (self.clean_prefix, command.qualified_name, command.signature) + + async def send_bot_help(self, mapping): + embed = discord.Embed(title="Koala Bot Help Menu", url = "https://koalabot.uk/", description="Koala bot is a open source project developed by university students throughout the UK aiming to help grow University society's to new heights!", color = 0x00aa6e) + embed.add_field(name = "Extensions", value = "Koala bot has many amazing functions called extensions. This makes it easy to mange which features you want enabled at any one time. You can find all of the commands to mange the extensions below.", inline = False) + + for cog, commands in mapping.items(): + filtered = await self.filter_commands(commands, sort = True) + command_signatures = [self.get_command_signature(c) for c in filtered] + if command_signatures: + cog_name = getattr(cog, "qualified_name", "Core") + embed.add_field(name = cog_name, value = "\n".join(command_signatures), inline = False) + + channel = self.get_destination() + await channel.send(embed = embed) + + async def send_pages(self): + destination = self.get_destination() + for page in self.paginator.pages: + embed = discord.Embed(description = page) + await destination.send(embed = embed) + @client.command() + async def paginate(ctx): + embed1 = discord.Embed(color=ctx.author.color).add_field(name="Example", value="Page 1") + embed2 = discord.Embed(color=ctx.author.color).add_field(name="Example", value="Page 2") + embed3 = discord.Embed(color=ctx.author.color).add_field(name="Example", value="Page 3") + paginator = DiscordUtils.Pagination.CustomEmbedPaginator(ctx) + paginator.add_reaction('⏮️', "first") + paginator.add_reaction('⏪', "back") + paginator.add_reaction('🔐', "lock") + paginator.add_reaction('⏩', "next") + paginator.add_reaction('⏭️', "last") + embeds = [embed1, embed2, embed3] + await paginator.run(embeds) + +client.help_command = HelpCom() + +"""@client.command(help = "Shows all bot's command usage in the server on a sorted list.", + aliases = ["br", "brrrr", "botranks", "botpos", "botposition", "botpositions"]) +async def botrank(ctx, bot: discord.Member): + pass""" + + + def is_owner(ctx): """ A command used to check if the user of a command is the owner, or the testing bot diff --git a/cogs/Info.py b/cogs/Info.py new file mode 100644 index 00000000..316995c0 --- /dev/null +++ b/cogs/Info.py @@ -0,0 +1,184 @@ +# Discord-ext-menu is needed, it can be installed via python -m pip install -U git+https://github.com/Rapptz/discord-ext-menus +import discord, KoalaBot, os +from discord.ext import commands, menus +from utils import KoalaDBManager +from collections import OrderedDict, deque, Counter +""" +KoalaBot Info Commands +Contains: userinfo, serverinfo, roleinfo and channelinfo +Author: SnowyJaguar#1034 +""" + +class Info(commands.Cog): + def __init__(self, client): + self.client = client + """ + Initialises local variables + :param bot: The bot client for this cog + """ + def perm_format(self, perm): + return perm.replace("_", " ").replace("guild", "server").title() + + @commands.command(aliases=["user-info", "userinfo", "memberinfo", "member-info"]) + async def whois(self, ctx, *, member : discord.Member=None): + guild = ctx.guild + member = member or ctx.author + key_perms = ["administrator", "manage_guild", "manage_roles", "manage_channels", "manage_messages", "manage_webhooks", "manage_nicknames", "manage_emojis", "kick_members", "mention_everyone"] + has_key = [perm for perm in key_perms if getattr(member.guild_permissions, perm)] + roles = member.roles[1:] + user = ctx.author + roles.reverse() + + if not roles: + + try: + embed = discord.Embed(colour = member.color, timestamp = ctx.message.created_at, description = member.mention) + embed = discord.Embed(title = f"{member.name}#{member.discriminator}", description = f"Status: **{member.status}**\n*{member.activity.name}*") + embed.set_author(name = f"{member.id}", icon_url = member.avatar_url) + embed.set_thumbnail(url = member.avatar_url) + embed.set_footer(text = f'{user.name}#{member.discriminator} | {user.id}') + + embed.add_field(name = "Joined Server:", value = member.joined_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = False) + embed.add_field(name = "Avatar", value = f"[Link]({member.avatar_url_as(static_format='png')})", inline = True) + embed.add_field(name = "Joined Discord:", value = member.created_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = True) + embed.add_field(name = f'Roles: 0', value = "None", inline = False) + + await ctx.send(embed = embed) + + except: + embed = discord.Embed(colour=member.color, timestamp=ctx.message.created_at, description=member.mention) + embed = discord.Embed(title = f"{member.name}#{member.discriminator}", description = f"Status: **{member.status}**") + embed.set_author(name = f"{member.id}", icon_url = member.avatar_url) + embed.set_thumbnail(url = member.avatar_url) + embed.set_footer(text = f'{user.name}#{member.discriminator} | {user.id}') + + embed.add_field(name = "Joined Server:", value = member.joined_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = True) + embed.add_field(name = "Avatar", value = f"[Link]({member.avatar_url_as(static_format='png')})", inline = True) + embed.add_field(name="Joined Discord:", value = member.created_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = True) + embed.add_field(name = f'Roles: 0', value = "None", inline = False) + await ctx.send(embed = embed) + return + if not has_key: + try: + embed = discord.Embed(colour = member.color, timestamp = ctx.message.created_at, description = member.mention) + embed = discord.Embed(title = f"{member.name}#{member.discriminator}", description = f"Status: **{member.status}**\n*{member.activity.name}*") + embed.set_author(name = f"{member.id}", icon_url = member.avatar_url) + embed.set_thumbnail(url = member.avatar_url) + embed.set_footer(text = f'{user.name}#{member.discriminator} | {user.id}') + + embed.add_field(name = "Joined Server:", value = member.joined_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = False) + embed.add_field(name = "Avatar", value = f"[Link]({member.avatar_url_as(static_format='png')})", inline = True) + embed.add_field(name = "Joined Discord:", value = member.created_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = True) + embed.add_field(name = f'Roles: {len(roles)}', value = " ".join([role.mention for role in roles]), inline = False) + await ctx.send(embed = embed) + + except: + + embed = discord.Embed(colour=member.color, timestamp=ctx.message.created_at, description=member.mention) + embed = discord.Embed(title = f"{member.name}#{member.discriminator}", description = f"Status: **{member.status}**") + embed.set_author(name = f"{member.id}", icon_url = member.avatar_url) + embed.set_thumbnail(url = member.avatar_url) + embed.set_footer(text = f'{user.name}#{member.discriminator} | {user.id}') + + embed.add_field(name = "Joined Server:", value = member.joined_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = True) + embed.add_field(name = "Avatar", value = f"[Link]({member.avatar_url_as(static_format='png')})", inline = True) + embed.add_field(name = "Joined Discord:", value=member.created_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = True) + embed.add_field(name = "Avatar", value=f"[Link]({member.avatar_url_as(static_format='png')})") + embed.add_field(name = f'Roles: {len(roles)}', value = " ".join([role.mention for role in roles]), inline = False) + await ctx.send(embed = embed) + return + if roles: + try: + embed = discord.Embed(colour = member.color, timestamp = ctx.message.created_at, description = member.mention) + embed = discord.Embed(title = f"{member.name}#{member.discriminator}", description = f"Status: **{member.status}**\n*{member.activity.name}*") + embed.set_author(name = f"{member.id}", icon_url = member.avatar_url) + embed.set_thumbnail(url = member.avatar_url) + embed.set_footer(text = f'{user.name}#{member.discriminator} | {user.id}') + + embed.add_field(name = "Joined Server:", value = member.joined_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = True) + embed.add_field(name = "Avatar", value = f"[Link]({member.avatar_url_as(static_format='png')})", inline = True) + embed.add_field(name = "Joined Discord:", value = member.created_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = True) + embed.add_field(name = f'Roles: {len(roles)}', value = " ".join([role.mention for role in roles]), inline = False) + embed.add_field(name = f'Core permissions', value = ", ".join(has_key).replace("_"," ").title(), inline = False) + await ctx.send(embed = embed) + + except: + embed = discord.Embed(colour = member.color, timestamp = ctx.message.created_at, description = member.mention) + embed = discord.Embed(title = f"{member.name}#{member.discriminator}", description = f"Status: **{member.status}**", color = 0x00aa6e) + embed.set_author(name = f"{member.id}", icon_url = member.avatar_url) + embed.set_thumbnail(url = member.avatar_url) + embed.set_footer(text = f'{user.name}#{user.discriminator} | {user.id}') + + embed.add_field(name = "Joined Server:", value = member.joined_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = True) + embed.add_field(name = "Avatar", value = f"[Link]({member.avatar_url_as(static_format='png')})") + embed.add_field(name = "Joined Discord:", value = member.created_at.strftime("%a, %b %w, %Y %I:%M %p"), inline = True) + embed.add_field(name = f'Roles: {len(roles)}', value = " ".join([role.mention for role in roles]), inline = False) + embed.add_field(name = f'Core permissions', value = ", ".join(has_key).replace("_"," ").title(), inline = False) + await ctx.send(embed = embed) + return + + @whois.error + async def whois_error(self, ctx, error): + if isinstance(error, commands.MemberNotFound): + embed = discord.Embed(description = f"<:error_1:840895769207898112> Couldn't find that user ", color = discord.Color.red()) + await ctx.send(embed = embed) + else: + print(error) + + @commands.command(aliases=["guildinfo", "serverstats", "guildstats", "server-info", "guild-info", "server-stats", "guild-stats"]) + async def serverinfo(self, ctx): + guild = ctx.guild + emoji_stats = Counter() + for emoji in guild.emojis: + if emoji.animated: + emoji_stats['animated'] += 1 + emoji_stats['animated_disabled'] += not emoji.available + else: + emoji_stats['regular'] += 1 + emoji_stats['disabled'] += not emoji.available + + fmt = f'Regular: {emoji_stats["regular"]}/{guild.emoji_limit} | Animated: {emoji_stats["animated"]}/{guild.emoji_limit}'\ + + if emoji_stats['disabled'] or emoji_stats['animated_disabled']: + fmt = f'{fmt}Disabled: {emoji_stats["disabled"]} regular, {emoji_stats["animated_disabled"]} animated\n' + + fmt = f'{fmt} | Total Emojis: {len(guild.emojis)}/{guild.emoji_limit*2}' + + embed = discord.Embed(title = f"{guild.name}", description = f"Server created on {guild.created_at.strftime('%a, %b %w, %Y %I:%M %p')}", color = 0x00aa6e) + embed.set_author(name = f"{guild.id}", icon_url = guild.icon_url) + embed.set_thumbnail(url = guild.icon_url) + # Cluster related Information for if/when the bot gets clustered. + #if ctx.guild: + #embed.set_footer(text = f"Cluster: {self.cluster} | Shard: {ctx.guild.shard_id + 1}") + #else: + #embed.set_footer(text = f"Cluster: {self.cluster} | Shard: {self.shard_count}") + embed.add_field(name = "Owner", value = f"{guild.owner.name}#{guild.owner.discriminator}" if guild.owner_id else "Unknown") + embed.add_field(name = "Icon", value = f"[Link]({guild.icon_url_as(static_format='png')})" if guild.icon else "*Not set*") + embed.add_field(name = "Region", value = guild.region.name.title()) + embed.add_field(name = "\nEmotes", value = fmt, inline = False) + embed.add_field(name = "Members", value = guild.member_count, inline = True) + embed.add_field(name = "Channels", value = len(guild.channels), inline = True) + embed.add_field(name = "Roles", value = len(guild.roles), inline = True) + embed.add_field(name = "Server Boosts", value = (guild.premium_subscription_count), inline = True) + embed.add_field(name = "Server Boost Level", value = (guild.premium_tier), inline = True) + await ctx.send(embed = embed) + + @commands.command(description = "Show a member's permission in a channel when specified.", usage = "permissions [channel]", aliases = ["perms"]) + async def permissions(self, ctx, member: discord.Member = None, channel: discord.TextChannel = None): + channel = channel or ctx.channel + if member is None: + member = ctx.author + permissions = channel.permissions_for(member) + embed = discord.Embed(title = "Permission Information", colour = 0x00aa6e) + embed.set_author(name = f"{member.name}#{member.discriminator}", icon_url = member.avatar_url) + embed.add_field(name = "Allowed", value = ", ".join([self.perm_format(name) for name, value in permissions if value]), inline = False) + embed.add_field(name = "Denied", value = ", ".join([self.perm_format(name) for name, value in permissions if not value]), inline = False) + await ctx.send(embed = embed) + +def setup(bot: KoalaBot) -> None: + """ + Load this cog to the KoalaBot. + :param bot: the bot client for KoalaBot + """ + bot.add_cog(Info(bot)) + print("Info is ready") \ No newline at end of file