From 87dfc03812a59b1299cdbde991a4bf7639e4205d Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 4 Mar 2024 19:53:12 -0500 Subject: [PATCH 01/34] fix(pterodactyl): don't ping users, roles, or @everyone/@here in console messages + ping only users in chat messages --- pterodactyl/websocket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pterodactyl/websocket.py b/pterodactyl/websocket.py index 5403725..9a17acf 100644 --- a/pterodactyl/websocket.py +++ b/pterodactyl/websocket.py @@ -58,7 +58,7 @@ async def establish_websocket_connection(coginstance: Pterodactyl) -> None: if content.startswith('['): pagified_content = pagify(content, delims=[" ", "\n"]) for page in pagified_content: - await channel.send(content=page) + await channel.send(content=page, allowed_mentions=discord.AllowedMentions.none()) server_message = await check_if_server_message(content) if server_message: @@ -230,7 +230,7 @@ async def send_chat_discord(coginstance: Pterodactyl, username: str, message: st webhook = discord.utils.get(webhooks, name="Pterodactyl Chat") if webhook is None: webhook = await channel.create_webhook(name="Pterodactyl Chat") - await webhook.send(content=message, username=username, avatar_url=avatar_url, allowed_mentions=discord.AllowedMentions.none()) + await webhook.send(content=message, username=username, avatar_url=avatar_url, allowed_mentions=discord.AllowedMentions(everyone=False, roles=False, users=True)) logger.debug("Chat message sent to Discord") else: logger.debug("Chat channel not set. Skipping sending chat message to Discord") From 34c34e745a4a61197ea04b2bec005352faef3580 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 4 Mar 2024 22:59:43 -0500 Subject: [PATCH 02/34] feat(pterodactyl): added a discord invite placeholder updated default chat command as well, and also a configuration value and related command --- .docs/pterodactyl/configuration.md | 6 ++++++ pterodactyl/config.py | 3 ++- pterodactyl/pterodactyl.py | 9 +++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.docs/pterodactyl/configuration.md b/.docs/pterodactyl/configuration.md index e37698f..ecf4982 100644 --- a/.docs/pterodactyl/configuration.md +++ b/.docs/pterodactyl/configuration.md @@ -62,6 +62,12 @@ This is to prevent the console channel from flooding and getting backed up by Di Default value: `None` +## `invite` + +This option determines what url the chat command will substitute in for the Discord invite placeholder. + +Default value: `None` + ## `ip` This option determines whether or not IP's will be redacted when posted in chat or to the console channel. diff --git a/pterodactyl/config.py b/pterodactyl/config.py index a8ad138..770c631 100644 --- a/pterodactyl/config.py +++ b/pterodactyl/config.py @@ -13,7 +13,7 @@ def register_config(config_obj: Config) -> None: join_regex=r"^\[\d{2}:\d{2}:\d{2} INFO\]: ([^<\n]+) joined the game$", leave_regex=r"^\[\d{2}:\d{2}:\d{2} INFO\]: ([^<\n]+) left the game$", achievement_regex=r"^\[\d{2}:\d{2}:\d{2} INFO\]: (.*) has (made the advancement|completed the challenge) \[(.*)\]$", - chat_command='tellraw @a ["",{"text":".$N ","color":".$C"},{"text":" (DISCORD): ","color":"blue"},{"text":".$M","color":"white"}]', + chat_command='tellraw @a ["",{"text":".$N ","color":".$C","insertion":"<@.$I>","hoverEvent":{"action":"show_text","contents":"Shift click to mention this user inside Discord"}},{"text":"(DISCORD):","color":"blue","clickEvent":{"action":"open_url","value":".$V"},"hoverEvent":{"action":"show_text","contents":"Click to join the Discord Server"}},{"text":" .$M","color":"white"}]', # noqa: E501 api_endpoint="minecraft", chat_channel=None, startup_msg='Server started!', @@ -21,5 +21,6 @@ def register_config(config_obj: Config) -> None: join_msg='Welcome to the server! 👋', leave_msg='Goodbye! 👋', mask_ip=True, + invite=None, regex_blacklist={}, ) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index de017f4..212cbd2 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -91,6 +91,7 @@ class Pterodactyl(commands.Cog): "M": message.content.replace('"',''), "N": message.author.display_name, "U": message.author.name, + "V": await config.invite() or "use [p]pterodactyl config invite to change me", } for key, value in placeholders.items(): command = command.replace('.$' + key, value) @@ -181,6 +182,12 @@ class Pterodactyl(commands.Cog): await config.console_channel.set(channel.id) await ctx.send(f"Console channel set to {channel.mention}") + @pterodactyl_config.command(name = "invite") + async def pterodactyl_config_invite(self, ctx: commands.Context, invite: str) -> None: + """Set the invite link for your server.""" + await config.invite.set(invite) + await ctx.send(f"Invite link set to {invite}") + @pterodactyl_config.group(name = "chat") async def pterodactyl_config_chat(self, ctx: commands.Context): """Configure chat settings.""" @@ -345,6 +352,7 @@ class Pterodactyl(commands.Cog): leave_msg = await config.leave_msg() mask_ip = await config.mask_ip() api_endpoint = await config.api_endpoint() + invite = await config.invite() regex_blacklist: dict = await config.regex_blacklist() embed = discord.Embed(color = await ctx.embed_color(), title="Pterodactyl Configuration") embed.description = f"""**Base URL:** {base_url} @@ -357,6 +365,7 @@ class Pterodactyl(commands.Cog): **Leave Message:** {leave_msg} **Mask IP:** {self.get_bool_str(mask_ip)} **API Endpoint:** `{api_endpoint}` + **Invite:** {invite} **Chat Command:** {box(chat_command, 'json')} **Chat Regex:** {box(chat_regex, 're')} From 3d3c5f708eb8743cbe5c559e76a26fdf3b8a9d99 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 4 Mar 2024 23:04:36 -0500 Subject: [PATCH 03/34] docs(pterodactyl): added new placeholder to chat command docs --- .docs/pterodactyl/configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.docs/pterodactyl/configuration.md b/.docs/pterodactyl/configuration.md index ecf4982..c216501 100644 --- a/.docs/pterodactyl/configuration.md +++ b/.docs/pterodactyl/configuration.md @@ -31,6 +31,7 @@ Available placeholders: - `.$M` - replaced with message content - `.$N` - replaced with author's display name (or guild nickname, if set) - `.$U` - replaced with the author's username (NOT display name, you should usually use `.$N`) +- `.$V` - replaced with the configured invite link Default value: From 0baad4629830378fca00a57b5da0b7d82c9b18c8 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 4 Mar 2024 23:06:51 -0500 Subject: [PATCH 04/34] misc(pterodactyl): temporarily adding a debug statement to test something --- pterodactyl/websocket.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pterodactyl/websocket.py b/pterodactyl/websocket.py index 9a17acf..decc2c7 100644 --- a/pterodactyl/websocket.py +++ b/pterodactyl/websocket.py @@ -34,6 +34,7 @@ async def establish_websocket_connection(coginstance: Pterodactyl) -> None: while True: # pylint: disable=too-many-nested-blocks message = json.loads(await websocket.recv()) + logger.debug("Received message from WebSocket:\n%s", json.dumps(message)) if message['event'] in ('token expiring', 'token expired'): logger.info("Received token expiring/expired event. Refreshing token.") websocket_credentials = await retrieve_websocket_credentials(coginstance) From d01985eea6ce0a3d8ddf9a6ed637de54777bde1e Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 4 Mar 2024 23:12:32 -0500 Subject: [PATCH 05/34] fix(pterodactyl): removed a bunch of useless/redundant logging statements --- pterodactyl/websocket.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/pterodactyl/websocket.py b/pterodactyl/websocket.py index decc2c7..926d47e 100644 --- a/pterodactyl/websocket.py +++ b/pterodactyl/websocket.py @@ -167,38 +167,31 @@ async def check_if_server_message(text: str) -> Union[bool, str]: return False async def check_if_chat_message(text: str) -> Union[bool, dict]: - logger.debug("Checking if message is a chat message") regex = await config.chat_regex() match: Optional[re.Match[str]] = re.match(regex, text) if match: groups = {"username": match.group(1), "message": match.group(2)} logger.debug("Message is a chat message\n%s", json.dumps(groups)) return groups - logger.debug("Message is not a chat message") return False async def check_if_join_message(text: str) -> Union[bool, str]: - logger.debug("Checking if message is a join message") regex = await config.join_regex() match: Optional[re.Match[str]] = re.match(regex, text) if match: logger.debug("Message is a join message") return match.group(1) - logger.debug("Message is not a join message") return False async def check_if_leave_message(text: str) -> Union[bool, str]: - logger.debug("Checking if message is a leave message") regex = await config.leave_regex() match: Optional[re.Match[str]] = re.match(regex, text) if match: logger.debug("Message is a leave message") return match.group(1) - logger.debug("Message is not a leave message") return False async def check_if_achievement_message(text: str) -> Union[bool, dict]: - logger.debug("Checking if message is an achievement message") regex = await config.achievement_regex() match: Optional[re.Match[str]] = re.match(regex, text) if match: @@ -207,9 +200,8 @@ async def check_if_achievement_message(text: str) -> Union[bool, dict]: groups["challenge"] = True else: groups["challenge"] = False - logger.debug("Message is an achievement message\n%s", json.dumps(groups)) + logger.debug("Message is an achievement message") return groups - logger.debug("Message is not an achievement message") return False async def get_info(username: str) -> Optional[dict]: @@ -218,7 +210,7 @@ async def get_info(username: str) -> Optional[dict]: async with aiohttp.ClientSession() as session: async with session.get(f"https://playerdb.co/api/player/{endpoint}/{username}") as response: if response.status == 200: - logger.debug("Player info retrieved for %s\n%s", username, json.dumps(await response.json())) + logger.debug("Player info retrieved for %s", username) return await response.json() logger.error("Failed to retrieve player info for %s: %s", username, response.status) return None @@ -234,7 +226,7 @@ async def send_chat_discord(coginstance: Pterodactyl, username: str, message: st await webhook.send(content=message, username=username, avatar_url=avatar_url, allowed_mentions=discord.AllowedMentions(everyone=False, roles=False, users=True)) logger.debug("Chat message sent to Discord") else: - logger.debug("Chat channel not set. Skipping sending chat message to Discord") + logger.warn("Chat channel not set. Skipping sending chat message to Discord") async def generate_join_leave_embed(username: str, join: bool) -> discord.Embed: embed = discord.Embed() @@ -261,7 +253,7 @@ async def generate_achievement_embed(username: str, achievement: str, challenge: return embed def mask_ip(string: str) -> str: - def check(match): + def check(match: re.Match[str]): ip = match.group(0) masked_ip = '.'.join(r'\*' * len(octet) for octet in ip.split('.')) return masked_ip From 13dba790b730918f8a1406b3df8043d2bd3c4c38 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 4 Mar 2024 23:13:25 -0500 Subject: [PATCH 06/34] fix(pterodactyl): removed leftover debug statement --- pterodactyl/websocket.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pterodactyl/websocket.py b/pterodactyl/websocket.py index 926d47e..c174ae6 100644 --- a/pterodactyl/websocket.py +++ b/pterodactyl/websocket.py @@ -34,7 +34,6 @@ async def establish_websocket_connection(coginstance: Pterodactyl) -> None: while True: # pylint: disable=too-many-nested-blocks message = json.loads(await websocket.recv()) - logger.debug("Received message from WebSocket:\n%s", json.dumps(message)) if message['event'] in ('token expiring', 'token expired'): logger.info("Received token expiring/expired event. Refreshing token.") websocket_credentials = await retrieve_websocket_credentials(coginstance) From 85d5316f43f86cb247c4dc1a55dd3495c2c3f806 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 4 Mar 2024 23:13:37 -0500 Subject: [PATCH 07/34] fix(pterodactyl): forgot two! --- pterodactyl/websocket.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pterodactyl/websocket.py b/pterodactyl/websocket.py index c174ae6..5d1aeab 100644 --- a/pterodactyl/websocket.py +++ b/pterodactyl/websocket.py @@ -156,13 +156,11 @@ def remove_ansi_escape_codes(text: str) -> str: return ansi_escape.sub('', text) async def check_if_server_message(text: str) -> Union[bool, str]: - logger.debug("Checking if message is a server message") regex = await config.server_regex() match: Optional[re.Match[str]] = re.match(regex, text) if match: logger.debug("Message is a server message") return match.group(1) - logger.debug("Message is not a server message") return False async def check_if_chat_message(text: str) -> Union[bool, dict]: From 75adf692c10fd63a68e329a4458eebc2693e76a0 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 4 Mar 2024 23:16:09 -0500 Subject: [PATCH 08/34] docs(pterodactyl): updated an outdated default value in the docs --- .docs/pterodactyl/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docs/pterodactyl/configuration.md b/.docs/pterodactyl/configuration.md index c216501..87349bd 100644 --- a/.docs/pterodactyl/configuration.md +++ b/.docs/pterodactyl/configuration.md @@ -36,7 +36,7 @@ Available placeholders: Default value: ```json -tellraw @a ["",{"text":".$N ","color":".$C"},{"text":" (DISCORD): ","color":"blue"},{"text":".$M","color":"white"}] +tellraw @a ["",{"text":".$N ","color":".$C","insertion":"<@.$I>","hoverEvent":{"action":"show_text","contents":"Shift click to mention this user inside Discord"}},{"text":"(DISCORD):","color":"blue","clickEvent":{"action":"open_url","value":".$V"},"hoverEvent":{"action":"show_text","contents":"Click to join the Discord Server"}},{"text":" .$M","color":"white"}] ``` ## `consolechannel` From aaba9ebd5959432a004542c221eb976c722ce464 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 4 Mar 2024 23:37:22 -0500 Subject: [PATCH 09/34] fix(backup): reduced minimum bot version to 3.5.2 --- backup/info.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup/info.json b/backup/info.json index fb779da..00321f0 100644 --- a/backup/info.json +++ b/backup/info.json @@ -7,7 +7,7 @@ "end_user_data_statement" : "This cog does not store end user data.", "hidden": false, "disabled": false, - "min_bot_version": "3.5.5", + "min_bot_version": "3.5.2", "max_bot_version": "3.5.5", "min_python_version": [3, 10, 0], "tags": [ From dec154fb4c91ff0bfad0bfe38d3dbf91acfe31e7 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 4 Mar 2024 23:43:14 -0500 Subject: [PATCH 10/34] fix(backup): changed version constraints again there have been no changes to downloader that break this since 3.5.0's release. however, 3.5.6 will be breaking most likely --- backup/backup.py | 1 - backup/info.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/backup/backup.py b/backup/backup.py index b973776..4977c97 100644 --- a/backup/backup.py +++ b/backup/backup.py @@ -17,7 +17,6 @@ from redbot.core.bot import Red from redbot.core.utils.chat_formatting import error, text_to_file - # pylint: disable=protected-access class Backup(commands.Cog): """A utility to make reinstalling repositories and cogs after migrating the bot far easier.""" diff --git a/backup/info.json b/backup/info.json index 00321f0..9694c65 100644 --- a/backup/info.json +++ b/backup/info.json @@ -7,7 +7,7 @@ "end_user_data_statement" : "This cog does not store end user data.", "hidden": false, "disabled": false, - "min_bot_version": "3.5.2", + "min_bot_version": "3.5.0", "max_bot_version": "3.5.5", "min_python_version": [3, 10, 0], "tags": [ From 8639615c49ad57dd26ba365966baef76a71f1028 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 4 Mar 2024 23:54:56 -0500 Subject: [PATCH 11/34] docs(): updated urls to www.coastalcommits.com from coastalcommits.com --- .docs/aurora/index.md | 2 +- .docs/backup.md | 2 +- .docs/bible.md | 2 +- .docs/nerdify.md | 2 +- .docs/pterodactyl/index.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.docs/aurora/index.md b/.docs/aurora/index.md index 48905f1..f6e5527 100644 --- a/.docs/aurora/index.md +++ b/.docs/aurora/index.md @@ -10,7 +10,7 @@ Aurora is a fully-featured moderation system. It is heavily inspired by Galactic ## Installation ```bash -[p]repo add seacogs https://coastalcommits.com/SeaswimmerTheFsh/SeaCogs +[p]repo add seacogs https://www.coastalcommits.com/SeaswimmerTheFsh/SeaCogs [p]cog install seacogs aurora [p]cog load aurora ``` diff --git a/.docs/backup.md b/.docs/backup.md index 550f7da..238ba8e 100644 --- a/.docs/backup.md +++ b/.docs/backup.md @@ -5,7 +5,7 @@ Backup allows you to export a JSON list of all of your installed repositories an ## Installation ```bash -[p]repo add seacogs https://coastalcommits.com/SeaswimmerTheFsh/SeaCogs +[p]repo add seacogs https://www.coastalcommits.com/SeaswimmerTheFsh/SeaCogs [p]cog install seacogs backup [p]cog load backup ``` diff --git a/.docs/bible.md b/.docs/bible.md index 2590187..b748de2 100644 --- a/.docs/bible.md +++ b/.docs/bible.md @@ -6,7 +6,7 @@ This cog does require an api key to work. ## Installation ```bash -[p]repo add seacogs https://coastalcommits.com/SeaswimmerTheFsh/SeaCogs +[p]repo add seacogs https://www.coastalcommits.com/SeaswimmerTheFsh/SeaCogs [p]cog install seacogs bible [p]cog load bible ``` diff --git a/.docs/nerdify.md b/.docs/nerdify.md index b7fe478..c1c50a9 100644 --- a/.docs/nerdify.md +++ b/.docs/nerdify.md @@ -5,7 +5,7 @@ Nerdify allows you to nerdify other people's text. ## Installation ```bash -[p]repo add seacogs https://coastalcommits.com/SeaswimmerTheFsh/SeaCogs +[p]repo add seacogs https://www.coastalcommits.com/SeaswimmerTheFsh/SeaCogs [p]cog install seacogs nerdify [p]cog load nerdify ``` diff --git a/.docs/pterodactyl/index.md b/.docs/pterodactyl/index.md index 748a465..bd3455e 100644 --- a/.docs/pterodactyl/index.md +++ b/.docs/pterodactyl/index.md @@ -10,7 +10,7 @@ Pterodactyl allows for connecting to a Pterodactyl server through websockets. It ## Installation ```bash -[p]repo add seacogs https://coastalcommits.com/SeaswimmerTheFsh/SeaCogs +[p]repo add seacogs https://www.coastalcommits.com/SeaswimmerTheFsh/SeaCogs [p]cog install seacogs pterodactyl [p]cog load aurora ``` From 093a6b90773b4d6e6cecf4c766fd2e794a26df21 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Tue, 5 Mar 2024 02:13:56 -0500 Subject: [PATCH 12/34] fix(backup): reduced python version constraint --- backup/info.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup/info.json b/backup/info.json index 9694c65..fccea3e 100644 --- a/backup/info.json +++ b/backup/info.json @@ -9,7 +9,7 @@ "disabled": false, "min_bot_version": "3.5.0", "max_bot_version": "3.5.5", - "min_python_version": [3, 10, 0], + "min_python_version": [3, 9, 0], "tags": [ "utility", "backup", From b2f27f949050870c25b6ddc7015511df8c32bddf Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Tue, 5 Mar 2024 02:16:32 -0500 Subject: [PATCH 13/34] feat(pterodactyl): added confirmation prompts to the power commands --- pterodactyl/pterodactyl.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index 212cbd2..fab4389 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -122,9 +122,15 @@ class Pterodactyl(commands.Cog): return await ctx.send("Server is already running.") if current_status in ["starting", "stopping"]: return await ctx.send("Another power action is already in progress.") - message = await ctx.send("Sending websocket command to start server...") - await self.websocket.send(json.dumps({"event": "set state", "args": ["start"]})) - await message.edit(content="Server starting...") + view = ConfirmView(ctx.author, disable_buttons=True) + message = await ctx.send("Are you sure you want to start the server?", view=view) + await view.wait() + if view.result is True: + await ctx.message("Sending websocket command to start server...") + await self.websocket.send(json.dumps({"event": "set state", "args": ["start"]})) + await message.edit(content="Server starting...") + else: + await message.edit(content="Cancelled.") @pterodactyl_power.command(name = "stop") async def pterodactyl_power_stop(self, ctx: commands.Context) -> None: @@ -134,9 +140,15 @@ class Pterodactyl(commands.Cog): return await ctx.send("Server is already stopped.") if current_status in ["starting", "stopping"]: return await ctx.send("Another power action is already in progress.") - message = await ctx.send("Sending websocket command to stop server...") - await self.websocket.send(json.dumps({"event": "set state", "args": ["stop"]})) - await message.edit(content="Server stopping...") + view = ConfirmView(ctx.author, disable_buttons=True) + message = await ctx.send("Are you sure you want to stop the server?", view=view) + await view.wait() + if view.result is True: + await message.edit("Sending websocket command to stop server...") + await self.websocket.send(json.dumps({"event": "set state", "args": ["stop"]})) + await message.edit(content="Server stopping...") + else: + await message.edit(content="Cancelled.") @pterodactyl_power.command(name = "restart") async def pterodactyl_power_restart(self, ctx: commands.Context) -> None: @@ -144,9 +156,15 @@ class Pterodactyl(commands.Cog): current_status = await config.current_status() if current_status in ["starting", "stopping"]: return await ctx.send("Another power action is already in progress.") - message = await ctx.send("Sending websocket command to restart server...") - await self.websocket.send(json.dumps({"event": "set state", "args": ["restart"]})) - await message.edit(content="Server restarting...") + view = ConfirmView(ctx.author, disable_buttons=True) + message = await ctx.send("Are you sure you want to restart the server?", view=view) + await view.wait() + if view.result is True: + await message.edit("Sending websocket command to restart server...") + await self.websocket.send(json.dumps({"event": "set state", "args": ["restart"]})) + await message.edit(content="Server restarting...") + else: + await message.edit(content="Cancelled.") @pterodactyl.group(autohelp = True, name = "config", aliases = ["settings", "set"]) @commands.is_owner() From df92bc34cc35b4fa67b21bc581a9fae0a9627746 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Tue, 5 Mar 2024 02:18:11 -0500 Subject: [PATCH 14/34] fix(pterodactyl): fixed some bugs --- pterodactyl/pterodactyl.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index fab4389..42b7ccc 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -126,11 +126,11 @@ class Pterodactyl(commands.Cog): message = await ctx.send("Are you sure you want to start the server?", view=view) await view.wait() if view.result is True: - await ctx.message("Sending websocket command to start server...") + await message.edit(content="Sending websocket command to start server...", view=None) await self.websocket.send(json.dumps({"event": "set state", "args": ["start"]})) await message.edit(content="Server starting...") else: - await message.edit(content="Cancelled.") + await message.edit(content="Cancelled.", view=None) @pterodactyl_power.command(name = "stop") async def pterodactyl_power_stop(self, ctx: commands.Context) -> None: @@ -144,11 +144,11 @@ class Pterodactyl(commands.Cog): message = await ctx.send("Are you sure you want to stop the server?", view=view) await view.wait() if view.result is True: - await message.edit("Sending websocket command to stop server...") + await message.edit(content="Sending websocket command to stop server...", view=None) await self.websocket.send(json.dumps({"event": "set state", "args": ["stop"]})) await message.edit(content="Server stopping...") else: - await message.edit(content="Cancelled.") + await message.edit(content="Cancelled.", view=None) @pterodactyl_power.command(name = "restart") async def pterodactyl_power_restart(self, ctx: commands.Context) -> None: @@ -160,11 +160,11 @@ class Pterodactyl(commands.Cog): message = await ctx.send("Are you sure you want to restart the server?", view=view) await view.wait() if view.result is True: - await message.edit("Sending websocket command to restart server...") + await message.edit(content="Sending websocket command to restart server...", view=None) await self.websocket.send(json.dumps({"event": "set state", "args": ["restart"]})) await message.edit(content="Server restarting...") else: - await message.edit(content="Cancelled.") + await message.edit(content="Cancelled.", view=None) @pterodactyl.group(autohelp = True, name = "config", aliases = ["settings", "set"]) @commands.is_owner() From 80cb729e72cb0221e33e54144bfe27a74c957e1e Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Tue, 5 Mar 2024 02:19:59 -0500 Subject: [PATCH 15/34] fix(pterodactyl): make sure views get removed properly --- pterodactyl/pterodactyl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index 42b7ccc..b616479 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -128,7 +128,7 @@ class Pterodactyl(commands.Cog): if view.result is True: await message.edit(content="Sending websocket command to start server...", view=None) await self.websocket.send(json.dumps({"event": "set state", "args": ["start"]})) - await message.edit(content="Server starting...") + await message.edit(content="Server starting...", view=None) else: await message.edit(content="Cancelled.", view=None) @@ -146,7 +146,7 @@ class Pterodactyl(commands.Cog): if view.result is True: await message.edit(content="Sending websocket command to stop server...", view=None) await self.websocket.send(json.dumps({"event": "set state", "args": ["stop"]})) - await message.edit(content="Server stopping...") + await message.edit(content="Server stopping...", view=None) else: await message.edit(content="Cancelled.", view=None) @@ -162,7 +162,7 @@ class Pterodactyl(commands.Cog): if view.result is True: await message.edit(content="Sending websocket command to restart server...", view=None) await self.websocket.send(json.dumps({"event": "set state", "args": ["restart"]})) - await message.edit(content="Server restarting...") + await message.edit(content="Server restarting...", view=None) else: await message.edit(content="Cancelled.", view=None) From 52be531807095a661eaac7edbbc4fb5fa348aa07 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Tue, 5 Mar 2024 02:24:20 -0500 Subject: [PATCH 16/34] fix(pterodactyl): type hints --- pterodactyl/pterodactyl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index b616479..baa9724 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -115,7 +115,7 @@ class Pterodactyl(commands.Cog): """Send power actions to the server.""" @pterodactyl_power.command(name = "start") - async def pterodactyl_power_start(self, ctx: commands.Context) -> None: + async def pterodactyl_power_start(self, ctx: commands.Context) -> Optional[discord.Message]: """Start the server.""" current_status = await config.current_status() if current_status == "running": @@ -133,7 +133,7 @@ class Pterodactyl(commands.Cog): await message.edit(content="Cancelled.", view=None) @pterodactyl_power.command(name = "stop") - async def pterodactyl_power_stop(self, ctx: commands.Context) -> None: + async def pterodactyl_power_stop(self, ctx: commands.Context) -> Optional[discord.Message]: """Stop the server.""" current_status = await config.current_status() if current_status == "stopped": @@ -151,7 +151,7 @@ class Pterodactyl(commands.Cog): await message.edit(content="Cancelled.", view=None) @pterodactyl_power.command(name = "restart") - async def pterodactyl_power_restart(self, ctx: commands.Context) -> None: + async def pterodactyl_power_restart(self, ctx: commands.Context) -> Optional[discord.Message]: """Restart the server.""" current_status = await config.current_status() if current_status in ["starting", "stopping"]: From 8c58e1746e701ad0f7419fd15b26199f84f1e8b2 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Tue, 5 Mar 2024 02:25:58 -0500 Subject: [PATCH 17/34] feat(pterodactyl): added ptero power kill command --- pterodactyl/pterodactyl.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index baa9724..9855806 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -166,6 +166,22 @@ class Pterodactyl(commands.Cog): else: await message.edit(content="Cancelled.", view=None) + @pterodactyl_power.command(name = "kill") + async def pterodactyl_power_kill(self, ctx: commands.Context) -> Optional[discord.Message]: + """Kill the server.""" + current_status = await config.current_status() + if current_status == 'stopped': + return await ctx.send("Server is already stopped.") + view = ConfirmView(ctx.author, disable_buttons=True) + message = await ctx.send("**⚠️ Forcefully killing the server process can corrupt data in some cases.**\nAre you sure you want to kill the server?", view=view) + await view.wait() + if view.result is True: + await message.edit(content="Sending websocket command to kill server...", view=None) + await self.websocket.send(json.dumps({"event": "set state", "args": ["kill"]})) + await message.edit(content="Server stopping... (forcefully killed)", view=None) + else: + await message.edit(content="Cancelled.", view=None) + @pterodactyl.group(autohelp = True, name = "config", aliases = ["settings", "set"]) @commands.is_owner() async def pterodactyl_config(self, ctx: commands.Context) -> None: From 9d64c15a877d38aa55ff8567260036762a309094 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Tue, 5 Mar 2024 02:28:10 -0500 Subject: [PATCH 18/34] =?UTF-8?q?misc(pterodactyl):=20added=20another=20?= =?UTF-8?q?=E2=9A=A0=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pterodactyl/pterodactyl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index 9855806..ff78c84 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -173,7 +173,7 @@ class Pterodactyl(commands.Cog): if current_status == 'stopped': return await ctx.send("Server is already stopped.") view = ConfirmView(ctx.author, disable_buttons=True) - message = await ctx.send("**⚠️ Forcefully killing the server process can corrupt data in some cases.**\nAre you sure you want to kill the server?", view=view) + message = await ctx.send("**⚠️ Forcefully killing the server process can corrupt data in some cases. ⚠️**\nAre you sure you want to kill the server?", view=view) await view.wait() if view.result is True: await message.edit(content="Sending websocket command to kill server...", view=None) From 64ab2fbf82ba2f48385a9123382f93a1d9459209 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 00:00:15 -0500 Subject: [PATCH 19/34] feat(pterodactyl): added a pterodactyl command command to execute commands on the server and made pterodactyl command and pterodactyl power into hybrid commands --- pterodactyl/pterodactyl.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index ff78c84..3ade407 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -7,7 +7,7 @@ import websockets from pydactyl import PterodactylClient from redbot.core import commands from redbot.core.bot import Red -from redbot.core.utils.chat_formatting import box +from redbot.core.utils.chat_formatting import box, error from redbot.core.utils.views import ConfirmView from pterodactyl.config import config, register_config @@ -109,7 +109,24 @@ class Pterodactyl(commands.Cog): async def pterodactyl(self, ctx: commands.Context) -> None: """Pterodactyl allows you to manage your Pterodactyl Panel from Discord.""" - @pterodactyl.group(autohelp = True, name = "power") + @pterodactyl.hybrid_command(name = "command", aliases = ["cmd", "execute", "exec"]) + @commands.admin() + async def pterodactyl_command(self, ctx: commands.Context, *, command: str) -> None: + """Send a command to the server console.""" + channel = self.bot.get_channel(await config.console_channel()) + if channel: + await channel.send(f"Received console command from {ctx.author.id}: {command[:1900]}") + try: + await self.websocket.send(json.dumps({"event": "send command", "args": [command]})) + await ctx.send(f"Command sent to server. {box(command, 'json')}") + except websockets.exceptions.ConnectionClosed as e: + logger.error("WebSocket connection closed: %s", e) + await ctx.send(error("WebSocket connection closed.")) + self.task.cancel() + self.retry_counter = 0 + self.task = self.get_task() + + @pterodactyl.hybrid_group(autohelp = True, name = "power") @commands.admin() async def pterodactyl_power(self, ctx: commands.Context) -> None: """Send power actions to the server.""" From f707b7009752011ae8f5e764dae2c8750020cf01 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 00:13:43 -0500 Subject: [PATCH 20/34] fix(pterodactyl): fixed broken slash commands --- pterodactyl/pterodactyl.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index 3ade407..7f4d078 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -105,11 +105,11 @@ class Pterodactyl(commands.Cog): self.retry_counter = 0 self.task = self.get_task() - @commands.group(autohelp = True, name = "pterodactyl", aliases = ["ptero"]) + @commands.hybrid_group(autohelp = True, name = "pterodactyl", aliases = ["ptero"]) async def pterodactyl(self, ctx: commands.Context) -> None: """Pterodactyl allows you to manage your Pterodactyl Panel from Discord.""" - @pterodactyl.hybrid_command(name = "command", aliases = ["cmd", "execute", "exec"]) + @pterodactyl.command(name = "command", aliases = ["cmd", "execute", "exec"]) @commands.admin() async def pterodactyl_command(self, ctx: commands.Context, *, command: str) -> None: """Send a command to the server console.""" @@ -126,7 +126,7 @@ class Pterodactyl(commands.Cog): self.retry_counter = 0 self.task = self.get_task() - @pterodactyl.hybrid_group(autohelp = True, name = "power") + @pterodactyl.group(autohelp = True, name = "power") @commands.admin() async def pterodactyl_power(self, ctx: commands.Context) -> None: """Send power actions to the server.""" @@ -199,7 +199,7 @@ class Pterodactyl(commands.Cog): else: await message.edit(content="Cancelled.", view=None) - @pterodactyl.group(autohelp = True, name = "config", aliases = ["settings", "set"]) + @pterodactyl.group(autohelp = True, name = "config", aliases = ["settings", "set"], with_app_command = False) @commands.is_owner() async def pterodactyl_config(self, ctx: commands.Context) -> None: """Configure Pterodactyl settings.""" From 1bb7e22b954542fc6ff1c7846da69039ea7bd25c Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 00:14:52 -0500 Subject: [PATCH 21/34] fix(pterodactyl): fixed another issue with hybrid commands --- pterodactyl/pterodactyl.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index 7f4d078..ec07688 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -239,7 +239,7 @@ class Pterodactyl(commands.Cog): await config.invite.set(invite) await ctx.send(f"Invite link set to {invite}") - @pterodactyl_config.group(name = "chat") + @pterodactyl_config.group(name = "chat", with_app_command = False) async def pterodactyl_config_chat(self, ctx: commands.Context): """Configure chat settings.""" @@ -258,7 +258,7 @@ class Pterodactyl(commands.Cog): await config.chat_command.set(command) await ctx.send(f"Chat command set to:\n{box(command, 'json')}") - @pterodactyl_config.group(name = "regex") + @pterodactyl_config.group(name = "regex", with_app_command = False) async def pterodactyl_config_regex(self, ctx: commands.Context) -> None: """Set regex patterns.""" @@ -302,7 +302,7 @@ class Pterodactyl(commands.Cog): await config.achievement_regex.set(regex) await ctx.send(f"Achievement regex set to:\n{box(regex, 'regex')}") - @pterodactyl_config.group(name = "messages", aliases = ['msg', 'msgs', 'message']) + @pterodactyl_config.group(name = "messages", aliases = ['msg', 'msgs', 'message'], with_app_command = False) async def pterodactyl_config_messages(self, ctx: commands.Context): """Configure message settings.""" @@ -345,7 +345,7 @@ class Pterodactyl(commands.Cog): await config.api_endpoint.set(endpoint) await ctx.send(f"API endpoint set to {endpoint}") - @pterodactyl_config_regex.group(name = "blacklist", aliases = ['block', 'blocklist']) + @pterodactyl_config_regex.group(name = "blacklist", aliases = ['block', 'blocklist'], with_app_command = False) async def pterodactyl_config_regex_blacklist(self, ctx: commands.Context): """Blacklist regex patterns.""" From f033f6a4830474ef6c2aa183d3326fe02e8b1c12 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 00:21:51 -0500 Subject: [PATCH 22/34] fix(pterodactyl): maybe fixed hybrid config commands, if this doesn't work, I'll move configuration commands to a separate command --- pterodactyl/pterodactyl.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index ec07688..4883fdd 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -199,7 +199,7 @@ class Pterodactyl(commands.Cog): else: await message.edit(content="Cancelled.", view=None) - @pterodactyl.group(autohelp = True, name = "config", aliases = ["settings", "set"], with_app_command = False) + @pterodactyl.hybrid_group(autohelp = True, name = "config", aliases = ["settings", "set"], with_app_command = False) @commands.is_owner() async def pterodactyl_config(self, ctx: commands.Context) -> None: """Configure Pterodactyl settings.""" @@ -239,7 +239,7 @@ class Pterodactyl(commands.Cog): await config.invite.set(invite) await ctx.send(f"Invite link set to {invite}") - @pterodactyl_config.group(name = "chat", with_app_command = False) + @pterodactyl_config.hybrid_group(name = "chat", with_app_command = False) async def pterodactyl_config_chat(self, ctx: commands.Context): """Configure chat settings.""" @@ -258,7 +258,7 @@ class Pterodactyl(commands.Cog): await config.chat_command.set(command) await ctx.send(f"Chat command set to:\n{box(command, 'json')}") - @pterodactyl_config.group(name = "regex", with_app_command = False) + @pterodactyl_config.hybrid_group(name = "regex", with_app_command = False) async def pterodactyl_config_regex(self, ctx: commands.Context) -> None: """Set regex patterns.""" @@ -302,7 +302,7 @@ class Pterodactyl(commands.Cog): await config.achievement_regex.set(regex) await ctx.send(f"Achievement regex set to:\n{box(regex, 'regex')}") - @pterodactyl_config.group(name = "messages", aliases = ['msg', 'msgs', 'message'], with_app_command = False) + @pterodactyl_config.hybrid_group(name = "messages", aliases = ['msg', 'msgs', 'message'], with_app_command = False) async def pterodactyl_config_messages(self, ctx: commands.Context): """Configure message settings.""" @@ -345,7 +345,7 @@ class Pterodactyl(commands.Cog): await config.api_endpoint.set(endpoint) await ctx.send(f"API endpoint set to {endpoint}") - @pterodactyl_config_regex.group(name = "blacklist", aliases = ['block', 'blocklist'], with_app_command = False) + @pterodactyl_config_regex.hybrid_group(name = "blacklist", aliases = ['block', 'blocklist'], with_app_command = False) async def pterodactyl_config_regex_blacklist(self, ctx: commands.Context): """Blacklist regex patterns.""" From bbb54f0f55147f616c2df891fb41a11020dedefd Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 00:56:50 -0500 Subject: [PATCH 23/34] feat(pterodactyl): fixed slash commands --- pterodactyl/pterodactyl.py | 191 +++++++++++++++++++++++-------------- 1 file changed, 119 insertions(+), 72 deletions(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index 4883fdd..478a184 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -1,11 +1,12 @@ import asyncio import json -from typing import Mapping, Optional +from typing import Mapping, Optional, Union import discord import websockets from pydactyl import PterodactylClient -from redbot.core import commands +from redbot.core import app_commands, commands +from redbot.core.app_commands import Choice from redbot.core.bot import Red from redbot.core.utils.chat_formatting import box, error from redbot.core.utils.views import ConfirmView @@ -97,6 +98,80 @@ class Pterodactyl(commands.Cog): command = command.replace('.$' + key, value) return command + async def power(self, ctx: Union[discord.Interaction, commands.Context], action: str, action_ing: str, warning: str = '') -> None: + if isinstance(ctx, discord.Interaction): + author = ctx.user + else: + author = ctx.author + + current_status = await config.current_status() + + if current_status == action_ing: + if isinstance(ctx, discord.Interaction): + return await ctx.response.send_message(f"Server is already {action_ing}.", ephemeral=True) + else: + return await ctx.send(f"Server is already {action_ing}.") + + if current_status in ["starting", "stopping"]: + if isinstance(ctx, discord.Interaction): + return await ctx.response.send_message("Another power action is already in progress.", ephemeral=True) + return await ctx.send("Another power action is already in progress.") + + view = ConfirmView(author, disable_buttons=True) + + if isinstance(ctx, discord.Interaction): + await ctx.response.send_message(f"{warning}Are you sure you want to {action} the server?", view=view) + else: + message = await ctx.send(f"{warning}Are you sure you want to {action} the server?", view=view) + + await view.wait() + + if view.result is True: + if isinstance(ctx, discord.Interaction): + await ctx.response.edit_message(content=f"Sending websocket command to {action} server...", view=None) + else: + await message.edit(content=f"Sending websocket command to {action} server...", view=None) + + await self.websocket.send(json.dumps({"event": "set state", "args": [action]})) + + if isinstance(ctx, discord.Interaction): + await ctx.response.edit_message(content=f"Server {action_ing}", view=None) + else: + await message.edit(content=f"Server {action_ing}", view=None) + + else: + if isinstance(ctx, discord.Interaction): + await ctx.response.edit_message(content="Cancelled.", view=None) + else: + await message.edit(content="Cancelled.", view=None) + + async def send_command(self, ctx: Union[discord.Interaction, commands.Context], command: str): + channel = self.bot.get_channel(await config.console_channel()) + if isinstance(ctx, discord.Interaction): + if channel: + await channel.send(f"Received console command from {ctx.user.id}: {command[:1900]}") + try: + await self.websocket.send(json.dumps({"event": "send command", "args": [command]})) + await ctx.response.send_message(f"Command sent to server. {box(command, 'json')}", ephemeral=True) + except websockets.exceptions.ConnectionClosed as e: + logger.error("WebSocket connection closed: %s", e) + await ctx.response.send_message(error("WebSocket connection closed.")) + self.task.cancel() + self.retry_counter = 0 + self.task = self.get_task() + else: + if channel: + await channel.send(f"Received console command from {ctx.author.id}: {command[:1900]}") + try: + await self.websocket.send(json.dumps({"event": "send command", "args": [command]})) + await ctx.send(f"Command sent to server. {box(command, 'json')}") + except websockets.exceptions.ConnectionClosed as e: + logger.error("WebSocket connection closed: %s", e) + await ctx.send(error("WebSocket connection closed.")) + self.task.cancel() + self.retry_counter = 0 + self.task = self.get_task() + @commands.Cog.listener() async def on_red_api_tokens_update(self, service_name: str, api_tokens: Mapping[str,str]): # pylint: disable=unused-argument if service_name == "pterodactyl": @@ -105,7 +180,38 @@ class Pterodactyl(commands.Cog): self.retry_counter = 0 self.task = self.get_task() - @commands.hybrid_group(autohelp = True, name = "pterodactyl", aliases = ["ptero"]) + slash_pterodactyl = app_commands.Group(name="pterodactyl", description="Pterodactyl allows you to manage your Pterodactyl Panel from Discord.") + + @slash_pterodactyl.command(name = "command", description = "Send a command to the server console.") + async def slash_pterodactyl_command(self, interaction: discord.Interaction, command: str) -> None: + """Send a command to the server console. + + Parameters: + ----------- + command: str + The command to send to the server.""" + return await self.send_command(interaction, command) + + @slash_pterodactyl.command(name = "power", description = "Send power actions to the server.") + @app_commands.choices(action=[ + Choice(name="Start", value="start"), + Choice(name="Stop", value="stop"), + Choice(name="Restart", value="restart"), + Choice(name="⚠️ Kill ⚠️", value="kill") + ]) + @app_commands.describe("action", "The action to perform on the server.") + async def slash_pterodactyl_power(self, interaction: discord.Interaction, action: app_commands.Choice[str]) -> None: + """Send power actions to the server. + + Parameters: + ----------- + action: app_commands.Choice[str] + The action to perform on the server.""" + if action.value == "kill": + return await self.power(interaction, action.value, "stopping... (forcefully killed)", warning="**⚠️ Forcefully killing the server process can corrupt data in some cases. ⚠️**\n") + return await self.power(interaction, action.value, f"{action.value}ing...") + + @commands.group(autohelp = True, name = "pterodactyl", aliases = ["ptero"]) async def pterodactyl(self, ctx: commands.Context) -> None: """Pterodactyl allows you to manage your Pterodactyl Panel from Discord.""" @@ -113,18 +219,7 @@ class Pterodactyl(commands.Cog): @commands.admin() async def pterodactyl_command(self, ctx: commands.Context, *, command: str) -> None: """Send a command to the server console.""" - channel = self.bot.get_channel(await config.console_channel()) - if channel: - await channel.send(f"Received console command from {ctx.author.id}: {command[:1900]}") - try: - await self.websocket.send(json.dumps({"event": "send command", "args": [command]})) - await ctx.send(f"Command sent to server. {box(command, 'json')}") - except websockets.exceptions.ConnectionClosed as e: - logger.error("WebSocket connection closed: %s", e) - await ctx.send(error("WebSocket connection closed.")) - self.task.cancel() - self.retry_counter = 0 - self.task = self.get_task() + return await self.send_command(ctx, command) @pterodactyl.group(autohelp = True, name = "power") @commands.admin() @@ -134,72 +229,24 @@ class Pterodactyl(commands.Cog): @pterodactyl_power.command(name = "start") async def pterodactyl_power_start(self, ctx: commands.Context) -> Optional[discord.Message]: """Start the server.""" - current_status = await config.current_status() - if current_status == "running": - return await ctx.send("Server is already running.") - if current_status in ["starting", "stopping"]: - return await ctx.send("Another power action is already in progress.") - view = ConfirmView(ctx.author, disable_buttons=True) - message = await ctx.send("Are you sure you want to start the server?", view=view) - await view.wait() - if view.result is True: - await message.edit(content="Sending websocket command to start server...", view=None) - await self.websocket.send(json.dumps({"event": "set state", "args": ["start"]})) - await message.edit(content="Server starting...", view=None) - else: - await message.edit(content="Cancelled.", view=None) + return await self.power(ctx, "start", "starting...") @pterodactyl_power.command(name = "stop") async def pterodactyl_power_stop(self, ctx: commands.Context) -> Optional[discord.Message]: """Stop the server.""" - current_status = await config.current_status() - if current_status == "stopped": - return await ctx.send("Server is already stopped.") - if current_status in ["starting", "stopping"]: - return await ctx.send("Another power action is already in progress.") - view = ConfirmView(ctx.author, disable_buttons=True) - message = await ctx.send("Are you sure you want to stop the server?", view=view) - await view.wait() - if view.result is True: - await message.edit(content="Sending websocket command to stop server...", view=None) - await self.websocket.send(json.dumps({"event": "set state", "args": ["stop"]})) - await message.edit(content="Server stopping...", view=None) - else: - await message.edit(content="Cancelled.", view=None) + return await self.power(ctx, "stop", "stopping...") @pterodactyl_power.command(name = "restart") async def pterodactyl_power_restart(self, ctx: commands.Context) -> Optional[discord.Message]: """Restart the server.""" - current_status = await config.current_status() - if current_status in ["starting", "stopping"]: - return await ctx.send("Another power action is already in progress.") - view = ConfirmView(ctx.author, disable_buttons=True) - message = await ctx.send("Are you sure you want to restart the server?", view=view) - await view.wait() - if view.result is True: - await message.edit(content="Sending websocket command to restart server...", view=None) - await self.websocket.send(json.dumps({"event": "set state", "args": ["restart"]})) - await message.edit(content="Server restarting...", view=None) - else: - await message.edit(content="Cancelled.", view=None) + return await self.power(ctx, "restart", "restarting...") @pterodactyl_power.command(name = "kill") async def pterodactyl_power_kill(self, ctx: commands.Context) -> Optional[discord.Message]: """Kill the server.""" - current_status = await config.current_status() - if current_status == 'stopped': - return await ctx.send("Server is already stopped.") - view = ConfirmView(ctx.author, disable_buttons=True) - message = await ctx.send("**⚠️ Forcefully killing the server process can corrupt data in some cases. ⚠️**\nAre you sure you want to kill the server?", view=view) - await view.wait() - if view.result is True: - await message.edit(content="Sending websocket command to kill server...", view=None) - await self.websocket.send(json.dumps({"event": "set state", "args": ["kill"]})) - await message.edit(content="Server stopping... (forcefully killed)", view=None) - else: - await message.edit(content="Cancelled.", view=None) + return await self.power(ctx, "kill", "stopping... (forcefully killed)", warning="**⚠️ Forcefully killing the server process can corrupt data in some cases. ⚠️**\n") - @pterodactyl.hybrid_group(autohelp = True, name = "config", aliases = ["settings", "set"], with_app_command = False) + @pterodactyl.group(autohelp = True, name = "config", aliases = ["settings", "set"]) @commands.is_owner() async def pterodactyl_config(self, ctx: commands.Context) -> None: """Configure Pterodactyl settings.""" @@ -239,7 +286,7 @@ class Pterodactyl(commands.Cog): await config.invite.set(invite) await ctx.send(f"Invite link set to {invite}") - @pterodactyl_config.hybrid_group(name = "chat", with_app_command = False) + @pterodactyl_config.group(name = "chat") async def pterodactyl_config_chat(self, ctx: commands.Context): """Configure chat settings.""" @@ -258,7 +305,7 @@ class Pterodactyl(commands.Cog): await config.chat_command.set(command) await ctx.send(f"Chat command set to:\n{box(command, 'json')}") - @pterodactyl_config.hybrid_group(name = "regex", with_app_command = False) + @pterodactyl_config.group(name = "regex") async def pterodactyl_config_regex(self, ctx: commands.Context) -> None: """Set regex patterns.""" @@ -302,7 +349,7 @@ class Pterodactyl(commands.Cog): await config.achievement_regex.set(regex) await ctx.send(f"Achievement regex set to:\n{box(regex, 'regex')}") - @pterodactyl_config.hybrid_group(name = "messages", aliases = ['msg', 'msgs', 'message'], with_app_command = False) + @pterodactyl_config.group(name = "messages", aliases = ['msg', 'msgs', 'message']) async def pterodactyl_config_messages(self, ctx: commands.Context): """Configure message settings.""" @@ -345,7 +392,7 @@ class Pterodactyl(commands.Cog): await config.api_endpoint.set(endpoint) await ctx.send(f"API endpoint set to {endpoint}") - @pterodactyl_config_regex.hybrid_group(name = "blacklist", aliases = ['block', 'blocklist'], with_app_command = False) + @pterodactyl_config_regex.group(name = "blacklist", aliases = ['block', 'blocklist'],) async def pterodactyl_config_regex_blacklist(self, ctx: commands.Context): """Blacklist regex patterns.""" From dd62b7d7ce1e40e75b526c8501606e5ce2e284bb Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 00:59:14 -0500 Subject: [PATCH 24/34] fix(pterodactyl): whoops! --- pterodactyl/pterodactyl.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index 478a184..17c594e 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -199,7 +199,6 @@ class Pterodactyl(commands.Cog): Choice(name="Restart", value="restart"), Choice(name="⚠️ Kill ⚠️", value="kill") ]) - @app_commands.describe("action", "The action to perform on the server.") async def slash_pterodactyl_power(self, interaction: discord.Interaction, action: app_commands.Choice[str]) -> None: """Send power actions to the server. From 41a8d575d4f209ca11f45fc93442263c6316b7af Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 01:03:36 -0500 Subject: [PATCH 25/34] fix(pterodactyl): fixed InteractionResponded error when using a power slash command --- pterodactyl/pterodactyl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index 17c594e..0822172 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -128,14 +128,14 @@ class Pterodactyl(commands.Cog): if view.result is True: if isinstance(ctx, discord.Interaction): - await ctx.response.edit_message(content=f"Sending websocket command to {action} server...", view=None) + await ctx.edit_original_response(content=f"Sending websocket command to {action} server...", view=None) else: await message.edit(content=f"Sending websocket command to {action} server...", view=None) await self.websocket.send(json.dumps({"event": "set state", "args": [action]})) if isinstance(ctx, discord.Interaction): - await ctx.response.edit_message(content=f"Server {action_ing}", view=None) + await ctx.edit_original_response(content=f"Server {action_ing}", view=None) else: await message.edit(content=f"Server {action_ing}", view=None) From f059145681495f26d0d41e8da3f572842e3607ce Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 01:04:27 -0500 Subject: [PATCH 26/34] fix(pterodactyl): missed one! --- pterodactyl/pterodactyl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index 0822172..9a9c931 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -141,7 +141,7 @@ class Pterodactyl(commands.Cog): else: if isinstance(ctx, discord.Interaction): - await ctx.response.edit_message(content="Cancelled.", view=None) + await ctx.edit_original_response(content="Cancelled.", view=None) else: await message.edit(content="Cancelled.", view=None) From 497f6a0a1a206419bdec19e3fe218541aed1e8b7 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 01:32:27 -0500 Subject: [PATCH 27/34] fix(repo): changed all loggers to `red.seacogs.` instead of `red.sea.` --- aurora/utilities/logger.py | 2 +- backup/backup.py | 2 +- bible/bible.py | 2 +- pterodactyl/logger.py | 3 ++- pterodactyl/websocket.py | 5 ++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/aurora/utilities/logger.py b/aurora/utilities/logger.py index 84a7836..748b8e4 100644 --- a/aurora/utilities/logger.py +++ b/aurora/utilities/logger.py @@ -1,3 +1,3 @@ import logging -logger = logging.getLogger("red.sea.aurora") +logger = logging.getLogger("red.seacogs.aurora") diff --git a/backup/backup.py b/backup/backup.py index 4977c97..4577dd0 100644 --- a/backup/backup.py +++ b/backup/backup.py @@ -27,7 +27,7 @@ class Backup(commands.Cog): def __init__(self, bot: Red): super().__init__() self.bot = bot - self.logger = logging.getLogger("red.sea.backup") + self.logger = logging.getLogger("red.seacogs.backup") @commands.group(autohelp=True) @commands.is_owner() diff --git a/bible/bible.py b/bible/bible.py index dc809ca..963648c 100644 --- a/bible/bible.py +++ b/bible/bible.py @@ -31,7 +31,7 @@ class Bible(commands.Cog): self.config = Config.get_conf( self, identifier=481923957134912, force_registration=True ) - self.logger = logging.getLogger("red.sea.bible") + self.logger = logging.getLogger("red.seacogs.bible") self.config.register_global(bible="de4e12af7f28f599-02") self.config.register_user(bible=None) diff --git a/pterodactyl/logger.py b/pterodactyl/logger.py index a1781ab..4ccbf1e 100644 --- a/pterodactyl/logger.py +++ b/pterodactyl/logger.py @@ -1,3 +1,4 @@ import logging -logger = logging.getLogger('red.sea.pterodactyl') +logger = logging.getLogger('red.seacogs.pterodactyl') +websocket_logger = logging.getLogger('red.seacogs.pterodactyl.websocket') diff --git a/pterodactyl/websocket.py b/pterodactyl/websocket.py index 5d1aeab..1c72880 100644 --- a/pterodactyl/websocket.py +++ b/pterodactyl/websocket.py @@ -1,7 +1,6 @@ # pylint: disable=cyclic-import import json import re -from logging import getLogger from typing import Optional, Union import aiohttp @@ -11,7 +10,7 @@ from pydactyl import PterodactylClient from redbot.core.utils.chat_formatting import bold, pagify from pterodactyl.config import config -from pterodactyl.logger import logger +from pterodactyl.logger import logger, websocket_logger from pterodactyl.pterodactyl import Pterodactyl @@ -23,7 +22,7 @@ async def establish_websocket_connection(coginstance: Pterodactyl) -> None: websocket_credentials = await retrieve_websocket_credentials(coginstance) - async with websockets.connect(websocket_credentials['data']['socket'], origin=base_url, ping_timeout=60, logger=getLogger("red.sea.pterodactyl.websocket")) as websocket: + async with websockets.connect(websocket_credentials['data']['socket'], origin=base_url, ping_timeout=60, logger=websocket_logger) as websocket: logger.info("WebSocket connection established") auth_message = json.dumps({"event": "auth", "args": [websocket_credentials['data']['token']]}) From c65fdd698cd788e4a9dc862eb6b56eacbf9a8206 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 02:19:00 -0500 Subject: [PATCH 28/34] fix(pterodactyl): pylint fixes --- pterodactyl/pterodactyl.py | 3 +-- pterodactyl/websocket.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pterodactyl/pterodactyl.py b/pterodactyl/pterodactyl.py index 9a9c931..ba8c80a 100644 --- a/pterodactyl/pterodactyl.py +++ b/pterodactyl/pterodactyl.py @@ -109,8 +109,7 @@ class Pterodactyl(commands.Cog): if current_status == action_ing: if isinstance(ctx, discord.Interaction): return await ctx.response.send_message(f"Server is already {action_ing}.", ephemeral=True) - else: - return await ctx.send(f"Server is already {action_ing}.") + return await ctx.send(f"Server is already {action_ing}.") if current_status in ["starting", "stopping"]: if isinstance(ctx, discord.Interaction): diff --git a/pterodactyl/websocket.py b/pterodactyl/websocket.py index 1c72880..15d1cb0 100644 --- a/pterodactyl/websocket.py +++ b/pterodactyl/websocket.py @@ -222,7 +222,7 @@ async def send_chat_discord(coginstance: Pterodactyl, username: str, message: st await webhook.send(content=message, username=username, avatar_url=avatar_url, allowed_mentions=discord.AllowedMentions(everyone=False, roles=False, users=True)) logger.debug("Chat message sent to Discord") else: - logger.warn("Chat channel not set. Skipping sending chat message to Discord") + logger.warning("Chat channel not set. Skipping sending chat message to Discord") async def generate_join_leave_embed(username: str, join: bool) -> discord.Embed: embed = discord.Embed() From 2e5fa81eac64b96c7103846bdc9fc56d1792f714 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 02:19:22 -0500 Subject: [PATCH 29/34] fix(pterodactyl): use custom fork of pydactyl library to fix https://github.com/iamkubi/pydactyl/issues/82 --- pterodactyl/info.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pterodactyl/info.json b/pterodactyl/info.json index 8d8d875..0a10241 100644 --- a/pterodactyl/info.json +++ b/pterodactyl/info.json @@ -9,7 +9,7 @@ "disabled": false, "min_bot_version": "3.5.0", "min_python_version": [3, 8, 0], - "requirements": ["py-dactyl", "websockets"], + "requirements": ["git+https://github.com/SeaswimmerTheFsh/pydactyl", "websockets"], "tags": [ "pterodactyl", "minecraft", From b5362ff15399d9ed1ab06f29096221f7876d12a8 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 02:33:14 -0500 Subject: [PATCH 30/34] fix(pterodactyl): update PterodactylClient initialization to use my own logger instead of setting debug to true --- pterodactyl/websocket.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pterodactyl/websocket.py b/pterodactyl/websocket.py index 15d1cb0..ece4020 100644 --- a/pterodactyl/websocket.py +++ b/pterodactyl/websocket.py @@ -134,10 +134,7 @@ async def retrieve_websocket_credentials(coginstance: Pterodactyl) -> Optional[d coginstance.task.cancel() raise ValueError("Pterodactyl server ID not set. Please set it using `[p]pterodactyl config serverid`.") - #FIXME - pydactyl should not be overriding the global python logger, but until that issue is fixed, - # we need to set the pydactyl logger to debug so it doesn't ignore any non-error log - # relevant issue - https://github.com/iamkubi/pydactyl/issues/82 - client = PterodactylClient(base_url, api_key, debug=True).client + client = PterodactylClient(base_url, api_key, logger=logger).client coginstance.client = client websocket_credentials = client.servers.get_websocket(server_id) logger.debug("""Websocket connection details retrieved: From 9e826d6ba505879064df1bfed8c2263e8c1448f0 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 02:39:49 -0500 Subject: [PATCH 31/34] misc(pterodactyl): testing something --- pterodactyl/websocket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pterodactyl/websocket.py b/pterodactyl/websocket.py index ece4020..716e3d8 100644 --- a/pterodactyl/websocket.py +++ b/pterodactyl/websocket.py @@ -134,7 +134,7 @@ async def retrieve_websocket_credentials(coginstance: Pterodactyl) -> Optional[d coginstance.task.cancel() raise ValueError("Pterodactyl server ID not set. Please set it using `[p]pterodactyl config serverid`.") - client = PterodactylClient(base_url, api_key, logger=logger).client + client = PterodactylClient(base_url, api_key).client coginstance.client = client websocket_credentials = client.servers.get_websocket(server_id) logger.debug("""Websocket connection details retrieved: From ae31a61436a5c18f7a1bbc89913a2f192d3be5de Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 02:52:44 -0500 Subject: [PATCH 32/34] fix(pterodactyl): log websocket messages to VERBOSE (log level 5) and not DEBUG --- pterodactyl/logger.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pterodactyl/logger.py b/pterodactyl/logger.py index 4ccbf1e..260a23a 100644 --- a/pterodactyl/logger.py +++ b/pterodactyl/logger.py @@ -1,4 +1,14 @@ import logging logger = logging.getLogger('red.seacogs.pterodactyl') +class WebsocketLogger(logging.Logger): + def __init__(self, name, level=logging.NOTSET): + super().__init__(name, level) + + def debug(self, msg, *args, **kwargs): + self.log(logging.VERBOSE, msg, *args, **kwargs) + +logging.setLoggerClass(WebsocketLogger) websocket_logger = logging.getLogger('red.seacogs.pterodactyl.websocket') +logging.VERBOSE = 5 +logging.addLevelName(logging.VERBOSE, "VERBOSE") From 178a92559cdec5f302b9b47e303942df09ed0f5e Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 03:38:34 -0500 Subject: [PATCH 33/34] feat(repo): added help formatters for version numbers to cogs that have them and migrated to using red's inbuilt loggers instead of logging.getLogger --- aurora/aurora.py | 17 ++++++++++++++--- aurora/utilities/logger.py | 4 ++-- backup/backup.py | 21 ++++++++++++++++----- bible/bible.py | 20 +++++++++++++++----- nerdify/nerdify.py | 14 ++++++++++++-- pterodactyl/logger.py | 16 +++------------- 6 files changed, 62 insertions(+), 30 deletions(-) diff --git a/aurora/aurora.py b/aurora/aurora.py index 3053484..1f946f4 100644 --- a/aurora/aurora.py +++ b/aurora/aurora.py @@ -19,7 +19,8 @@ from pytimeparse2 import disable_dateutil, parse from redbot.core import app_commands, commands, data_manager from redbot.core.app_commands import Choice from redbot.core.bot import Red -from redbot.core.utils.chat_formatting import box, error, warning +from redbot.core.utils.chat_formatting import (box, error, humanize_list, + warning) from aurora.importers.aurora import ImportAuroraView from aurora.importers.galacticbot import ImportGalacticBotView @@ -46,8 +47,8 @@ class Aurora(commands.Cog): It is heavily inspired by GalacticBot, and is designed to be a more user-friendly alternative to Red's core Mod cogs. This cog stores all of its data in an SQLite database.""" - __author__ = "SeaswimmerTheFsh" - __version__ = "2.0.5" + __author__ = ["SeaswimmerTheFsh"] + __version__ = "2.0.6" async def red_delete_data_for_user(self, *, requester, user_id: int): if requester == "discord_deleted_user": @@ -86,6 +87,16 @@ class Aurora(commands.Cog): disable_dateutil() self.handle_expiry.start() + def format_help_for_context(self, ctx: commands.Context) -> str: + pre_processed = super().format_help_for_context(ctx) or "" + n = "\n" if "\n\n" not in pre_processed else "" + text = [ + f"{pre_processed}{n}", + f"Cog Version: **{self.__version__}**", + f"Author: {humanize_list(self.__author__)}", + ] + return "\n".join(text) + async def cog_load(self): """This method prepares the database schema for all of the guilds the bot is currently in.""" guilds: list[discord.Guild] = self.bot.guilds diff --git a/aurora/utilities/logger.py b/aurora/utilities/logger.py index 748b8e4..9ea3c2f 100644 --- a/aurora/utilities/logger.py +++ b/aurora/utilities/logger.py @@ -1,3 +1,3 @@ -import logging +from red_commons.logging import getLogger -logger = logging.getLogger("red.seacogs.aurora") +logger = getLogger("red.seacogs.aurora") diff --git a/backup/backup.py b/backup/backup.py index 4577dd0..e1f12b5 100644 --- a/backup/backup.py +++ b/backup/backup.py @@ -7,27 +7,38 @@ import contextlib import json -import logging import re +from red_commons.logging import getLogger from redbot.cogs.downloader import errors from redbot.cogs.downloader.converters import InstalledCog from redbot.core import commands from redbot.core.bot import Red -from redbot.core.utils.chat_formatting import error, text_to_file +from redbot.core.utils.chat_formatting import (error, humanize_list, + text_to_file) # pylint: disable=protected-access class Backup(commands.Cog): """A utility to make reinstalling repositories and cogs after migrating the bot far easier.""" - __author__ = "SeaswimmerTheFsh" - __version__ = "1.0.0" + __author__ = ["SeaswimmerTheFsh"] + __version__ = "1.0.1" def __init__(self, bot: Red): super().__init__() self.bot = bot - self.logger = logging.getLogger("red.seacogs.backup") + self.logger = getLogger("red.seacogs.backup") + + def format_help_for_context(self, ctx: commands.Context) -> str: + pre_processed = super().format_help_for_context(ctx) or "" + n = "\n" if "\n\n" not in pre_processed else "" + text = [ + f"{pre_processed}{n}", + f"Cog Version: **{self.__version__}**", + f"Author: {humanize_list(self.__author__)}", + ] + return "\n".join(text) @commands.group(autohelp=True) @commands.is_owner() diff --git a/bible/bible.py b/bible/bible.py index 963648c..5b7305f 100644 --- a/bible/bible.py +++ b/bible/bible.py @@ -5,14 +5,14 @@ # ____) | __/ (_| \__ \\ V V /| | | | | | | | | | | | __/ | # |_____/ \___|\__,_|___/ \_/\_/ |_|_| |_| |_|_| |_| |_|\___|_| -import logging import random import aiohttp from discord import Embed +from red_commons.logging import getLogger from redbot.core import Config, commands from redbot.core.bot import Red -from redbot.core.utils.chat_formatting import error +from redbot.core.utils.chat_formatting import error, humanize_list import bible.errors from bible.models import Version @@ -21,8 +21,8 @@ from bible.models import Version class Bible(commands.Cog): """Retrieve Bible verses from the API.bible API.""" - __author__ = "SeaswimmerTheFsh" - __version__ = "1.0.0" + __author__ = ["SeaswimmerTheFsh"] + __version__ = "1.0.1" def __init__(self, bot: Red): super().__init__() @@ -31,10 +31,20 @@ class Bible(commands.Cog): self.config = Config.get_conf( self, identifier=481923957134912, force_registration=True ) - self.logger = logging.getLogger("red.seacogs.bible") + self.logger = getLogger("red.seacogs.bible") self.config.register_global(bible="de4e12af7f28f599-02") self.config.register_user(bible=None) + def format_help_for_context(self, ctx: commands.Context) -> str: + pre_processed = super().format_help_for_context(ctx) or "" + n = "\n" if "\n\n" not in pre_processed else "" + text = [ + f"{pre_processed}{n}", + f"Cog Version: **{self.__version__}**", + f"Author: {humanize_list(self.__author__)}", + ] + return "\n".join(text) + async def translate_book_name(self, bible_id: str, book_name: str) -> str: """Translate a book name to a book ID.""" book_name_list = [ diff --git a/nerdify/nerdify.py b/nerdify/nerdify.py index 333be8e..dc97886 100644 --- a/nerdify/nerdify.py +++ b/nerdify/nerdify.py @@ -17,12 +17,22 @@ from redbot.core.utils import chat_formatting, common_filters class Nerdify(commands.Cog): """Nerdify your text.""" - __author__ = "SeaswimmerTheFsh" - __version__ = "1.3.2" + __author__ = ["SeaswimmerTheFsh"] + __version__ = "1.3.3" def __init__(self, bot): self.bot = bot + def format_help_for_context(self, ctx: commands.Context) -> str: + pre_processed = super().format_help_for_context(ctx) or "" + n = "\n" if "\n\n" not in pre_processed else "" + text = [ + f"{pre_processed}{n}", + f"Cog Version: **{self.__version__}**", + f"Author: {chat_formatting.humanize_list(self.__author__)}", + ] + return "\n".join(text) + @commands.command(aliases=["nerd"]) async def nerdify( self, ctx: commands.Context, *, text: Optional[str] = None diff --git a/pterodactyl/logger.py b/pterodactyl/logger.py index 260a23a..482fefc 100644 --- a/pterodactyl/logger.py +++ b/pterodactyl/logger.py @@ -1,14 +1,4 @@ -import logging +from red_commons.logging import getLogger -logger = logging.getLogger('red.seacogs.pterodactyl') -class WebsocketLogger(logging.Logger): - def __init__(self, name, level=logging.NOTSET): - super().__init__(name, level) - - def debug(self, msg, *args, **kwargs): - self.log(logging.VERBOSE, msg, *args, **kwargs) - -logging.setLoggerClass(WebsocketLogger) -websocket_logger = logging.getLogger('red.seacogs.pterodactyl.websocket') -logging.VERBOSE = 5 -logging.addLevelName(logging.VERBOSE, "VERBOSE") +logger = getLogger('red.seacogs.pterodactyl') +websocket_logger = getLogger('red.seacogs.pterodactyl.websocket') From fdb785ffd798d42b5b44cbb6d5f7d99905a6f215 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Thu, 7 Mar 2024 13:47:40 -0500 Subject: [PATCH 34/34] feat(backup): allow for retrieving backup exports from bot messages if you reply to them --- backup/backup.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backup/backup.py b/backup/backup.py index e1f12b5..cde40fa 100644 --- a/backup/backup.py +++ b/backup/backup.py @@ -97,8 +97,11 @@ class Backup(commands.Cog): try: export = json.loads(await ctx.message.attachments[0].read()) except (json.JSONDecodeError, IndexError): - await ctx.send(error("Please provide a valid JSON export file.")) - return + try: + export = json.loads(await ctx.message.reference.resolved.attachments[0].read()) + except (json.JSONDecodeError, IndexError): + await ctx.send(error("Please provide a valid JSON export file.")) + return downloader = ctx.bot.get_cog("Downloader") if downloader is None: