diff --git a/cogs/checkip.py b/cogs/checkip.py index db0f2ae..b8f222a 100644 --- a/cogs/checkip.py +++ b/cogs/checkip.py @@ -2,12 +2,14 @@ from discord import Embed from mcstatus import JavaServer from utils import Utils + + class CheckIP(commands.Cog): def __init__(self, bot): self.bot = bot @bridge.bridge_command(aliases=["checkserverip", "check"], description="Checks if an Aternos-IP is free to use.") - async def checkip(self, ctx, address = None): + async def checkip(self, ctx, address=None): if address is None: return await ctx.respond("Please provide a Aternos server ip!\nExample: example.aternos.me") if not address.endswith(".aternos.me"): @@ -16,18 +18,22 @@ async def checkip(self, ctx, address = None): return await ctx.respond("Please provide a valid Aternos server ip!\nExample: example.aternos.me") nip = address.split(".")[0] if len(nip) > 20: - return await ctx.respond("Aternos IPs can only be 20 characters long, please try a shorter one. Yours is " + str(len(nip)) + " characters long.") + return await ctx.respond( + "Aternos IPs can only be 20 characters long, please try a shorter one. Yours is " + str( + len(nip)) + " characters long.") if len(nip) < 4: - return await ctx.respond("Aternos IPs must be at least 4 characters long, please try a longer one. Yours is " + str(len(nip)) + " characters long.") + return await ctx.respond( + "Aternos IPs must be at least 4 characters long, please try a longer one. Yours is " + str( + len(nip)) + " characters long.") await ctx.defer() embed = Embed() server = await JavaServer.async_lookup(address) stat = await server.async_status() if stat.version.name == "⚠ Error": - embed.description=f"**{address}** is free to use!\nTo use it as your server address, head to **[the options of your server](https://aternos.org/options)**" + embed.description = f"**{address}** is free to use!\nTo use it as your server address, head to **[the options of your server](https://aternos.org/options)**" embed.colour = Utils.Colors.green else: - embed.description=f"**{address}** is already taken!" + embed.description = f"**{address}** is already taken!" embed.colour = Utils.Colors.red await ctx.respond(embed=embed) diff --git a/cogs/cogs.py b/cogs/cogs.py index 752b6d5..0d78f8f 100644 --- a/cogs/cogs.py +++ b/cogs/cogs.py @@ -2,8 +2,10 @@ from discord.ext.commands import slash_command from discord.ext import commands from discord import Option -#from discord.errors import ExtensionAlreadyLoaded +# from discord.errors import ExtensionAlreadyLoaded from utils import Utils + + class Cogs(commands.Cog): def __init__(self, bot): self.bot = bot @@ -18,7 +20,8 @@ def getcogs(self, ctx): cogs.append(file[:-3]) return cogs - @slash_command(description='Only the owners of the bot can run this command', guild_ids=Utils.get_data()['FeatureGuilds']) + @slash_command(description='Only the owners of the bot can run this command', + guild_ids=Utils.get_data()['FeatureGuilds']) async def cogs(self, ctx, action: Option(choices=["Load", "Unload", "Reload"]), cog: Option(autocomplete=getcogs)): if ctx.author.id not in self.info['Owners']: return @@ -46,5 +49,6 @@ async def cogs(self, ctx, action: Option(choices=["Load", "Unload", "Reload"]), raise error await ctx.respond(f"{action}ed {cog} and reloaded all commands!") + def setup(bot): bot.add_cog(Cogs(bot)) diff --git a/cogs/error.py b/cogs/error.py index 3f9a206..aaf400d 100644 --- a/cogs/error.py +++ b/cogs/error.py @@ -1,4 +1,6 @@ from discord.ext import commands + + class Error(commands.Cog): def __init__(self, bot): self.bot = bot @@ -7,13 +9,14 @@ def __init__(self, bot): async def on_command_error(self, ctx, error): if isinstance(error, commands.CommandNotFound): return await ctx.respond("That command doesn't exist!") - await ctx.respond ("An unknown error has occured!\nThis has been logged") + await ctx.respond("An unknown error has occured!\nThis has been logged") raise error @commands.Cog.listener() async def on_application_command_error(self, ctx, error): - await ctx.respond ("An unknown error has occured!\nThis has been logged") + await ctx.respond("An unknown error has occured!\nThis has been logged") raise error + def setup(bot): bot.add_cog(Error(bot)) diff --git a/cogs/info.py b/cogs/info.py index 30c09bb..52b2fbb 100644 --- a/cogs/info.py +++ b/cogs/info.py @@ -3,6 +3,7 @@ from discord import Embed from utils import Utils + class Info(commands.Cog): def __init__(self, bot): self.bot = bot @@ -21,7 +22,7 @@ async def info(self, ctx): **Guilds:** {len(self.bot.guilds)} **Users:** {sum(x.member_count for x in self.bot.guilds)} -**API Latency:** {round(self.bot.latency*1000)}ms +**API Latency:** {round(self.bot.latency * 1000)}ms **Protocol Latency:** {latency}ms [[Invite]](https://discord.com/api/oauth2/authorize?client_id=889197952994791434&permissions=274878286912&scope=bot%20applications.commands) [[Support]](https://discord.gg/Ukr89GrMBk) [[Github]](https://github.com/BlackFurORG/pingernos) [[Privacy Policy]](https://gist.github.com/MiataBoy/20fda9024f277ea5eb2421adbebc2f23) [[Terms of Service]](https://gist.github.com/MiataBoy/81e96023a2aa055a038edab02e7e7792) @@ -29,5 +30,6 @@ async def info(self, ctx): embed.colour = Utils.Colors.blue await ctx.respond(embed=embed) + def setup(bot): bot.add_cog(Info(bot)) diff --git a/cogs/privacy.py b/cogs/privacy.py index 2003ed2..0dc2e80 100644 --- a/cogs/privacy.py +++ b/cogs/privacy.py @@ -1,16 +1,19 @@ from discord.ext import commands, bridge from discord import Embed from utils import Utils + + class Privacy(commands.Cog): def __init__(self, bot): self.bot = bot - @bridge.bridge_command(description = "Shows the privacy policy of the bot.") + @bridge.bridge_command(description="Shows the privacy policy of the bot.") async def privacy(self, ctx): embed = Embed() embed.description = f"{self.bot.user.name} saves a minimal amount of data to allow for its functionality. As we work on regaining full functionality, we do not currently collect anything On our database storage, we currently only have server IPs and guild IDs stored. For any concerns, Mail to miataboymx@gmail.com or join https://discord.gg/Ukr89GrMBk" embed.colour = Utils.Colors.blue await ctx.respond(embed=embed) + def setup(bot): bot.add_cog(Privacy(bot)) diff --git a/cogs/setserver.py b/cogs/setserver.py index 06e25ed..268656e 100644 --- a/cogs/setserver.py +++ b/cogs/setserver.py @@ -1,14 +1,31 @@ -from discord.ext import commands#, bridge +from discord.ext import commands, bridge +from utils import Utils + + class SetServer(commands.Cog): def __init__(self, bot): self.bot = bot - #@bridge.bridge_command(aliases=["set"], description="Set the default server to use if no argument is provided in the status command.") - #async def setserver(self, ctx, server = None): - # if server is None: - # return await ctx.respond("Please provide a server IP.") - # await ctx.defer() - #This is up to Miataboy to implement + @bridge.bridge_command(aliases=["set"], + description="Set the default server to use if no argument is provided in the status command.") + async def setserver(self, ctx, server=None): + if server is None: + return await ctx.respond( + "Please provide a server IP to register to this guild. If an IP is already registered, it'll be overwritten") + if not server.endswith(".aternos.me"): + server += ".aternos.me" + if server.count(".") > 2: + return await ctx.respond("Please provide a valid Aternos server ip!\nExample: example.aternos.me") + cursor = await Utils.mysql_login() + database = cursor.cursor() + database.execute( + "INSERT INTO server (guild_id, server_ip) VALUES (%s, %s) ON DUPLICATE KEY UPDATE server_ip = %s", + (ctx.guild_id, server, server)) + cursor.commit() + database.close() + cursor.close() + return await ctx.respond(f'The IP has been set to {server}. Use `status` without an argument to view it.') + def setup(bot): bot.add_cog(SetServer(bot)) diff --git a/cogs/status.py b/cogs/status.py index 29d118e..f7c99ec 100644 --- a/cogs/status.py +++ b/cogs/status.py @@ -2,15 +2,27 @@ from discord.ext import commands, bridge from discord import Embed, utils as dutils from utils import Utils + + class Status(commands.Cog): def __init__(self, bot): self.bot = bot @bridge.bridge_command(aliases=["s"], description="Get the server status") - async def status(self, ctx, serverip = None): + async def status(self, ctx, serverip=None): if serverip is None: - #Until Miataboy implements the default server, this will appear - return await ctx.respond("Please provide a valid Aternos server ip!\nExample: example.aternos.me") + cursor = await Utils.mysql_login() + database = cursor.cursor() + database.execute("SELECT server_ip FROM server WHERE guild_id = %s", [ctx.guild.id]) + try: + result = database.fetchone()[0] + except TypeError: + database.close() + cursor.close() + return await ctx.respond("Sorry, but this server does not have an IP registered. Please use `setserver` for that.") + serverip = result + database.close() + cursor.close() if not serverip.endswith(".aternos.me"): serverip += ".aternos.me" if serverip.count(".") > 2: @@ -22,18 +34,22 @@ async def status(self, ctx, serverip = None): return await ctx.respond("Uh oh! The protocol took too long to respond! This will likely fix itself.") embed = Embed(title=serverip) if stat.version.name == "§4● Offline": - embed.description = "We are not able to gather info from offline servers, sorry!\nProtocol Latency: " + str(round(stat.latency)) + "ms\n\nIf you believe this is wrong, please [join our discord server](https://discord.gg/G2AaJbvdHT)." + embed.description = "We are not able to gather info from offline servers, sorry!\nProtocol Latency: " + str( + round( + stat.latency)) + "ms\n\nIf you believe this is wrong, please [join our discord server](https://discord.gg/G2AaJbvdHT)." embed.colour = Utils.Colors.red embed.timestamp = dutils.utcnow() embed.set_footer(text="Command executed by " + ctx.author.name + "#" + ctx.author.discriminator) elif stat.version.name == "⚠ Error": - embed.description = "Server does not exist\nProtocol Latency: " + str(round(stat.latency)) + "ms\n\nIf you believe this is wrong, please [join our discord server](https://discord.gg/G2AaJbvdHT)." + embed.description = "Server does not exist\nProtocol Latency: " + str(round( + stat.latency)) + "ms\n\nIf you believe this is wrong, please [join our discord server](https://discord.gg/G2AaJbvdHT)." embed.colour = Utils.Colors.red embed.timestamp = dutils.utcnow() embed.set_footer(text="Command executed by " + ctx.author.name + "#" + ctx.author.discriminator) else: embed.add_field(name="**__Status__**", value="Online", inline=True) - embed.add_field(name="**__Players__**", value=str(stat.players.online) + "/" + str(stat.players.max), inline=True) + embed.add_field(name="**__Players__**", value=str(stat.players.online) + "/" + str(stat.players.max), + inline=True) embed.add_field(name="**__Software__**", value=stat.version.name, inline=True) embed.add_field(name="**__MOTD__**", value=Utils.remove_colors_from_string(stat.description), inline=False) embed.colour = Utils.Colors.green @@ -41,5 +57,6 @@ async def status(self, ctx, serverip = None): embed.set_footer(text="Command executed by " + ctx.author.name + "#" + ctx.author.discriminator) await ctx.respond(embed=embed) + def setup(bot): bot.add_cog(Status(bot)) diff --git a/main.py b/main.py index 5ae4293..37ec055 100644 --- a/main.py +++ b/main.py @@ -1,26 +1,36 @@ from discord import Intents, Status, Activity, ActivityType from discord.ext.bridge import Bot from utils import Utils + data = Utils.get_data() intents = Intents(guilds=True, guild_messages=True) -#intents.message_content = True #Uncomment this if you use prefixed command that are not mentions -bot = Bot(intents=intents, command_prefix=data['Prefix'], status=Status.dnd, activity=Activity(type=ActivityType.watching, name="you (prefix: @mention)")) -bot.load_extensions("cogs") #Loads all cogs in the cogs folder -bot.help_command = Utils.HelpCmd() #Disables the default help command +# intents.message_content = True #Uncomment this if you use prefixed command that are not mentions +bot = Bot(intents=intents, command_prefix=data['Prefix'], status=Status.dnd, + activity=Activity(type=ActivityType.watching, name="you (prefix: @mention)")) +bot.load_extensions("cogs") # Loads all cogs in the cogs folder +bot.help_command = Utils.HelpCmd() # Disables the default help command BOOTED = False + + @bot.listen() async def on_connect(): print('Connected to Discord!') + cursor = await Utils.mysql_login() + database = cursor.cursor() + database.execute("CREATE TABLE IF NOT EXISTS server (guild_id VARCHAR(255) PRIMARY KEY, server_ip TEXT NOT NULL)") + database.close() + @bot.listen() async def on_ready(): global BOOTED if BOOTED: - print ("Reconnect(?)") + print("Reconnect(?)") if not BOOTED: - #await bot.sync_commands() #You might need to uncomment this if the slash commands aren't appearing + # await bot.sync_commands() #You might need to uncomment this if the slash commands aren't appearing print(f'Logged in as {bot.user}') print('------') BOOTED = True + bot.run(data['Token']) diff --git a/requirements.txt b/requirements.txt index 17f5894..dbf3111 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ py-cord==2.4.0 python-dotenv==0.21.0 mcstatus==10.0.1 -asyncmy==0.2.5 \ No newline at end of file +asyncmy==0.2.5 +mysql-connector-python==8.0.32 \ No newline at end of file diff --git a/utils.py b/utils.py index 5f69f21..eae1457 100644 --- a/utils.py +++ b/utils.py @@ -3,29 +3,37 @@ from os import getenv from sys import exit as sysexit from discord.ext.commands import HelpCommand +import mysql.connector as mysql + try: from dotenv import load_dotenv + load_dotenv() except ModuleNotFoundError: print('You did not install the dotenv module! You will not be able to use a .env file.') try: from mcstatus import JavaServer + from mcstatus.pinger import PingResponse except ModuleNotFoundError: print('You did not install the mcstatus module! Exiting now...') sysexit() + + class Utils: - @staticmethod #This is a static method, you can call it without creating an instance of the class, but does not have access to the class or its attributes (self) + @staticmethod # This is a static method, you can call it without creating an instance of the class, but does not have access to the class or its attributes (self) def remove_colors_from_string(text) -> str: text = sub(r"§[0-9a-r]", "", text) return text + class Colors: blue = 0xadd8e6 red = 0xf04747 green = 0x90ee90 orange = 0xfaa61a + @staticmethod def get_data() -> dict: - usejson = False #Set to True to a config.json + usejson = False # Set to True to a config.json if usejson: try: with open('config.json', 'r', encoding="UTF-8") as file: @@ -58,13 +66,25 @@ def get_data() -> dict: print('You did not fill out the environment variables! Exiting now...') sysexit() return data + @staticmethod - async def get_server_status(serverip: str) -> dict: + async def get_server_status(serverip: str) -> PingResponse: server = await JavaServer.async_lookup(serverip) stat = await server.async_status() return stat + @staticmethod + async def mysql_login(): + data = Utils.get_data() + + return mysql.connect( + host=data['Database']['Host'], + user=data['Database']['User'], + password=data['Database']['Password'], + database=data['Database']['Database']) + class HelpCmd(HelpCommand): async def send_bot_help(self, mapping): channel = self.get_destination() - await channel.send("Type in `/` to see the commands!", reference=self.context.message, mention_author=False, delete_after=15) + await channel.send("Type in `/` to see the commands!", reference=self.context.message, mention_author=False, + delete_after=15)