Merge branch 'main' into aurora-hybrid
Some checks failed
Actions / Lint Code (Ruff & Pylint) (pull_request) Failing after 22s
Actions / Build Documentation (MkDocs) (pull_request) Successful in 27s

This commit is contained in:
Seaswimmer 2024-03-07 20:00:09 +00:00
commit 354b505e6e
Signed by: CoastalCommitsManagement
GPG key ID: 7E73189F651A553F
17 changed files with 228 additions and 84 deletions

View file

@ -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
```

View file

@ -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
```

View file

@ -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
```

View file

@ -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
```

View file

@ -31,11 +31,12 @@ 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:
```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`
@ -62,6 +63,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.

View file

@ -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
```

View file

@ -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

View file

@ -1,3 +1,3 @@
import logging
from red_commons.logging import getLogger
logger = logging.getLogger("red.sea.aurora")
logger = getLogger("red.seacogs.aurora")

View file

@ -7,28 +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.sea.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()
@ -86,6 +96,9 @@ class Backup(commands.Cog):
"""Import your installed repositories and cogs from an export file."""
try:
export = json.loads(await ctx.message.attachments[0].read())
except (json.JSONDecodeError, IndexError):
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

View file

@ -7,9 +7,9 @@
"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.0",
"max_bot_version": "3.5.5",
"min_python_version": [3, 10, 0],
"min_python_version": [3, 9, 0],
"tags": [
"utility",
"backup",

View file

@ -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.sea.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 = [

View file

@ -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

View file

@ -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={},
)

View file

@ -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",

View file

@ -1,3 +1,4 @@
import logging
from red_commons.logging import getLogger
logger = logging.getLogger('red.sea.pterodactyl')
logger = getLogger('red.seacogs.pterodactyl')
websocket_logger = getLogger('red.seacogs.pterodactyl.websocket')

View file

@ -1,13 +1,14 @@
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
from redbot.core.utils.chat_formatting import box, error
from redbot.core.utils.views import ConfirmView
from pterodactyl.config import config, register_config
@ -91,11 +92,85 @@ 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)
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)
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.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.edit_original_response(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.edit_original_response(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":
@ -104,48 +179,70 @@ class Pterodactyl(commands.Cog):
self.retry_counter = 0
self.task = self.get_task()
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")
])
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."""
@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."""
return await self.send_command(ctx, command)
@pterodactyl.group(autohelp = True, name = "power")
@commands.admin()
async def pterodactyl_power(self, ctx: commands.Context) -> None:
"""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":
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...")
return await self.power(ctx, "start", "starting...")
@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":
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...")
return await self.power(ctx, "stop", "stopping...")
@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"]:
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...")
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."""
return await self.power(ctx, "kill", "stopping... (forcefully killed)", warning="**⚠️ Forcefully killing the server process can corrupt data in some cases. ⚠️**\n")
@pterodactyl.group(autohelp = True, name = "config", aliases = ["settings", "set"])
@commands.is_owner()
@ -181,6 +278,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."""
@ -287,7 +390,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'],)
async def pterodactyl_config_regex_blacklist(self, ctx: commands.Context):
"""Blacklist regex patterns."""
@ -345,6 +448,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 +461,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')}

View file

@ -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']]})
@ -58,7 +57,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:
@ -135,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).client
coginstance.client = client
websocket_credentials = client.servers.get_websocket(server_id)
logger.debug("""Websocket connection details retrieved:
@ -156,48 +152,39 @@ 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]:
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:
@ -206,9 +193,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]:
@ -217,7 +203,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
@ -230,10 +216,10 @@ 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")
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()
@ -260,7 +246,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