From 7bd9531b5811140ec0f1dd274b7e971a0fa9dcf0 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 13 May 2024 19:26:13 -0400 Subject: [PATCH 01/83] feat(seautils): added the cog --- seautils/__init__.py | 5 +++++ seautils/info.json | 12 ++++++++++++ seautils/seautils.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 seautils/__init__.py create mode 100644 seautils/info.json create mode 100644 seautils/seautils.py diff --git a/seautils/__init__.py b/seautils/__init__.py new file mode 100644 index 0000000..dd217b4 --- /dev/null +++ b/seautils/__init__.py @@ -0,0 +1,5 @@ +from .seautils import SeaUtils + + +async def setup(bot): + await bot.add_cog(SeaUtils(bot)) diff --git a/seautils/info.json b/seautils/info.json new file mode 100644 index 0000000..f331eac --- /dev/null +++ b/seautils/info.json @@ -0,0 +1,12 @@ +{ + "author" : ["SeaswimmerTheFsh (seasw.)"], + "install_msg" : "Thank you for installing SeaUtils!\nYou can find the source code of this cog [here](https://coastalcommits.com/SeaswimmerTheFsh/SeaCogs).", + "name" : "SeaUtils", + "short" : "A collection of useful utilities.", + "description" : "A collection of useful utilities.", + "end_user_data_statement" : "This cog does not store end user data.", + "hidden": true, + "disabled": false, + "min_bot_version": "3.5.0", + "min_python_version": [3, 8, 0] +} diff --git a/seautils/seautils.py b/seautils/seautils.py new file mode 100644 index 0000000..c42fc0e --- /dev/null +++ b/seautils/seautils.py @@ -0,0 +1,42 @@ +# _____ _ +# / ____| (_) +# | (___ ___ __ _ _____ ___ _ __ ___ _ __ ___ ___ _ __ +# \___ \ / _ \/ _` / __\ \ /\ / / | '_ ` _ \| '_ ` _ \ / _ \ '__| +# ____) | __/ (_| \__ \\ V V /| | | | | | | | | | | | __/ | +# |_____/ \___|\__,_|___/ \_/\_/ |_|_| |_| |_|_| |_| |_|\___|_| + +import inspect + +from redbot.core import commands +from redbot.core.bot import Red +from redbot.core.utils import chat_formatting as cf + + +class SeaUtils(commands.Cog): + """A collection of random utilities.""" + + __author__ = ["SeaswimmerTheFsh"] + __version__ = "1.0.0" + + def __init__(self, bot: Red): + 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: {cf.humanize_list(self.__author__)}" + ] + return "\n".join(text) + + @commands.command(aliases=["source"]) + @commands.is_owner() + async def showcode(self, ctx: commands.Context, *, command: str): + """Show the code for a particular command.""" + try: + content = cf.pagify(inspect.getsource(self.bot.get_command(command).callback)) + await ctx.send_interactive(content, box_lang='py') + except OSError: + await ctx.send("Command not found.") From 516c0feeccfbcece8fbb13f34560f1093d0f689d Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 13 May 2024 20:17:00 -0400 Subject: [PATCH 02/83] fix(seautils): catch the attributeerror --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index c42fc0e..367ff3d 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -38,5 +38,5 @@ class SeaUtils(commands.Cog): try: content = cf.pagify(inspect.getsource(self.bot.get_command(command).callback)) await ctx.send_interactive(content, box_lang='py') - except OSError: + except (OSError, AttributeError): await ctx.send("Command not found.") From 59848fe85701f959ed337c6c94adee34db3700f4 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 13 May 2024 20:22:13 -0400 Subject: [PATCH 03/83] misc(seautils): added more aliases to showcode --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 367ff3d..c59d089 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -31,7 +31,7 @@ class SeaUtils(commands.Cog): ] return "\n".join(text) - @commands.command(aliases=["source"]) + @commands.command(aliases=["source", "src", "code", "showsource"]) @commands.is_owner() async def showcode(self, ctx: commands.Context, *, command: str): """Show the code for a particular command.""" From bb1aca83dd58f240864d8ebfc5c481ba5fb8b531 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 13 May 2024 21:09:02 -0400 Subject: [PATCH 04/83] feat(seautils): added some more functionality to showcode --- seautils/seautils.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index c59d089..374d28e 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -7,9 +7,11 @@ import inspect +from discord import Embed from redbot.core import commands from redbot.core.bot import Red from redbot.core.utils import chat_formatting as cf +from redbot.core.utils.views import SimpleMenu class SeaUtils(commands.Cog): @@ -36,7 +38,21 @@ class SeaUtils(commands.Cog): async def showcode(self, ctx: commands.Context, *, command: str): """Show the code for a particular command.""" try: - content = cf.pagify(inspect.getsource(self.bot.get_command(command).callback)) - await ctx.send_interactive(content, box_lang='py') + temp_content = [] + content = [] + for page in cf.pagify( + text=inspect.getsource(self.bot.get_command(command).callback), + escape_mass_mentions=True, + page_length = 1977 + ): + temp_content.append(cf.box(page, lang='py')) + + max_i = len(temp_content) + i = 1 + for page in temp_content: + content.append(f"**Page {i}/{max_i}**\n{page}") + i += 1 + await SimpleMenu(content, disable_after_timeout=True, timeout=180).start(ctx) except (OSError, AttributeError): - await ctx.send("Command not found.") + embed = Embed(title="Command not found!", color=await ctx.embed_color()) + await ctx.send(embed=embed, reference=ctx.message.to_reference(fail_if_not_exists=False)) From 84d2728d3af54d430f99d3dd70ef5f26d836a1b5 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 13 May 2024 21:11:15 -0400 Subject: [PATCH 05/83] misc(seautils): optimized showcode --- seautils/seautils.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 374d28e..b9f9ef8 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -38,19 +38,16 @@ class SeaUtils(commands.Cog): async def showcode(self, ctx: commands.Context, *, command: str): """Show the code for a particular command.""" try: - temp_content = [] - content = [] - for page in cf.pagify( + temp_content = cf.pagify( text=inspect.getsource(self.bot.get_command(command).callback), escape_mass_mentions=True, page_length = 1977 - ): - temp_content.append(cf.box(page, lang='py')) - + ) + content = [] max_i = len(temp_content) i = 1 for page in temp_content: - content.append(f"**Page {i}/{max_i}**\n{page}") + content.append(f"**Page {i}/{max_i}**\n{cf.box(page, lang='py')}") i += 1 await SimpleMenu(content, disable_after_timeout=True, timeout=180).start(ctx) except (OSError, AttributeError): From 059badaa9bc78525d62194c91106cec8e3d0e43b Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 13 May 2024 21:12:51 -0400 Subject: [PATCH 06/83] fix(seautils): use length_hint --- seautils/seautils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index b9f9ef8..66d877a 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -6,6 +6,7 @@ # |_____/ \___|\__,_|___/ \_/\_/ |_|_| |_| |_|_| |_| |_|\___|_| import inspect +import operator from discord import Embed from redbot.core import commands @@ -44,7 +45,7 @@ class SeaUtils(commands.Cog): page_length = 1977 ) content = [] - max_i = len(temp_content) + max_i = operator.length_hint(temp_content) i = 1 for page in temp_content: content.append(f"**Page {i}/{max_i}**\n{cf.box(page, lang='py')}") From 2dcbcb0a59cc86d12a48e973d11f581d3255447f Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 13 May 2024 21:14:15 -0400 Subject: [PATCH 07/83] fix(seautils): use ctx.embed_requested() --- seautils/seautils.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 66d877a..e4468ca 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -50,7 +50,10 @@ class SeaUtils(commands.Cog): for page in temp_content: content.append(f"**Page {i}/{max_i}**\n{cf.box(page, lang='py')}") i += 1 - await SimpleMenu(content, disable_after_timeout=True, timeout=180).start(ctx) + await SimpleMenu(pages=content, disable_after_timeout=True, timeout=180).start(ctx) except (OSError, AttributeError): - embed = Embed(title="Command not found!", color=await ctx.embed_color()) - await ctx.send(embed=embed, reference=ctx.message.to_reference(fail_if_not_exists=False)) + if ctx.embed_requested(): + embed = Embed(title="Command not found!", color=await ctx.embed_color()) + await ctx.send(embed=embed, reference=ctx.message.to_reference(fail_if_not_exists=False)) + else: + await ctx.send(content="Command not found!", reference=ctx.message.to_reference(fail_if_not_exists=False)) From 511659878899e1cff8ed19b845ed16fd46420633 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Fri, 17 May 2024 00:12:40 -0400 Subject: [PATCH 08/83] feat(seautils): add support for cogs and slash commands --- seautils/seautils.py | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index e4468ca..897baf5 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -7,10 +7,14 @@ import inspect import operator +from functools import partial, partialmethod +from typing import Any -from discord import Embed +from discord import Embed, app_commands +from discord.utils import CachedSlotProperty, cached_property from redbot.core import commands from redbot.core.bot import Red +from redbot.core.dev_commands import cleanup_code from redbot.core.utils import chat_formatting as cf from redbot.core.utils.views import SimpleMenu @@ -34,13 +38,34 @@ class SeaUtils(commands.Cog): ] return "\n".join(text) + def format_src(self, ctx: commands.Context, obj: Any) -> str: + """A large portion of this code is repurposed from Zephyrkul's RTFS cog. + https://github.com/Zephyrkul/FluffyCogs/blob/master/rtfs/rtfs.py""" + obj = inspect.unwrap(obj) + src: Any = getattr(obj, "__func__", obj) + if isinstance(obj, (commands.Command, app_commands.Command)): + src = obj.callback + elif isinstance(obj, (partial, partialmethod)): + src = obj.func + elif isinstance(obj, property): + src = obj.fget + elif isinstance(obj, (cached_property, CachedSlotProperty)): + src = obj.function + return inspect.getsource(src) + @commands.command(aliases=["source", "src", "code", "showsource"]) @commands.is_owner() - async def showcode(self, ctx: commands.Context, *, command: str): - """Show the code for a particular command.""" + async def showcode(self, ctx: commands.Context, *, object: str): + """Show the code for a particular object.""" try: + if object.startswith("/") and (obj := ctx.bot.tree.get_command(object[1:])): + text = self.format_src(ctx, obj) + elif obj := ctx.bot.get_cog(object): + text = self.format_src(ctx, type(obj)) + elif obj:= ctx.bot.get_command(object): + text = self.format_src(ctx, obj) temp_content = cf.pagify( - text=inspect.getsource(self.bot.get_command(command).callback), + text=cleanup_code(text), escape_mass_mentions=True, page_length = 1977 ) @@ -53,7 +78,7 @@ class SeaUtils(commands.Cog): await SimpleMenu(pages=content, disable_after_timeout=True, timeout=180).start(ctx) except (OSError, AttributeError): if ctx.embed_requested(): - embed = Embed(title="Command not found!", color=await ctx.embed_color()) + embed = Embed(title="Object not found!", color=await ctx.embed_color()) await ctx.send(embed=embed, reference=ctx.message.to_reference(fail_if_not_exists=False)) else: - await ctx.send(content="Command not found!", reference=ctx.message.to_reference(fail_if_not_exists=False)) + await ctx.send(content="Object not found!", reference=ctx.message.to_reference(fail_if_not_exists=False)) From 7019b9ffe5ad87ef0876b66189ba29409bba534d Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Fri, 17 May 2024 00:14:33 -0400 Subject: [PATCH 09/83] fix(seautils): catch an UnboundLocalError --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 897baf5..3bdf8b4 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -76,7 +76,7 @@ class SeaUtils(commands.Cog): content.append(f"**Page {i}/{max_i}**\n{cf.box(page, lang='py')}") i += 1 await SimpleMenu(pages=content, disable_after_timeout=True, timeout=180).start(ctx) - except (OSError, AttributeError): + except (OSError, AttributeError, UnboundLocalError): if ctx.embed_requested(): embed = Embed(title="Object not found!", color=await ctx.embed_color()) await ctx.send(embed=embed, reference=ctx.message.to_reference(fail_if_not_exists=False)) From d556ee3704f9a62d0c340eccee69efc3be3b7f61 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Fri, 17 May 2024 00:20:00 -0400 Subject: [PATCH 10/83] fix(seautils): minor syntax change --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 3bdf8b4..6790627 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -62,7 +62,7 @@ class SeaUtils(commands.Cog): text = self.format_src(ctx, obj) elif obj := ctx.bot.get_cog(object): text = self.format_src(ctx, type(obj)) - elif obj:= ctx.bot.get_command(object): + elif obj := ctx.bot.get_command(object): text = self.format_src(ctx, obj) temp_content = cf.pagify( text=cleanup_code(text), From 3fd91d977630f53e62f08f8a89d37ab8d82c95c0 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Fri, 17 May 2024 00:44:19 -0400 Subject: [PATCH 11/83] misc(emojiinfo): default slash command to ephemeral true --- emojiinfo/emojiinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emojiinfo/emojiinfo.py b/emojiinfo/emojiinfo.py index f3a520b..e6cbc99 100644 --- a/emojiinfo/emojiinfo.py +++ b/emojiinfo/emojiinfo.py @@ -91,7 +91,7 @@ class EmojiInfo(commands.Cog): emoji="What emoji would you like to get information on?", ephemeral="Would you like the response to be hidden?" ) - async def emoji_slash(self, interaction: discord.Interaction, emoji: str, ephemeral: bool = False) -> None: + async def emoji_slash(self, interaction: discord.Interaction, emoji: str, ephemeral: bool = True) -> None: """Retrieve information about an emoji.""" await interaction.response.defer(ephemeral=ephemeral) From d8758cfb1d4dc534867e2d055b222753917263ef Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Fri, 17 May 2024 00:46:25 -0400 Subject: [PATCH 12/83] misc(emojiinfo): verbosity --- emojiinfo/emojiinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emojiinfo/emojiinfo.py b/emojiinfo/emojiinfo.py index e6cbc99..8ec2a45 100644 --- a/emojiinfo/emojiinfo.py +++ b/emojiinfo/emojiinfo.py @@ -62,7 +62,7 @@ class EmojiInfo(commands.Cog): else: emoji_url = emoji.url - if emoji.id: + if emoji.id is not None: emoji_id = f"{bold('ID:')} `{emoji.id}`\n" markdown = f"`<{'a' if emoji.animated else ''}:{emoji.name}:{emoji.id}>`" name = f"{bold('Name:')} {emoji.name}\n" From c9a47603a7d777ca86c28f5225b16877249876b3 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Fri, 17 May 2024 00:48:14 -0400 Subject: [PATCH 13/83] fix(emojiinfo): add a debug logging call --- emojiinfo/emojiinfo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/emojiinfo/emojiinfo.py b/emojiinfo/emojiinfo.py index 8ec2a45..e464485 100644 --- a/emojiinfo/emojiinfo.py +++ b/emojiinfo/emojiinfo.py @@ -98,6 +98,7 @@ class EmojiInfo(commands.Cog): try: emoji: PartialEmoji = PartialEmoji.from_str(self, value=emoji) string, emoji_url, = await self.get_emoji_info(emoji) + self.logger.verbose(f"Emoji:\n{string}") except (IndexError, UnboundLocalError): return await interaction.followup.send("Please provide a valid emoji!") From d95c9b32555c5f4f37e1b3b31e8a475097a48a56 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Fri, 17 May 2024 00:57:30 -0400 Subject: [PATCH 14/83] fix(emojiinfo): oops lmao --- emojiinfo/emojiinfo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/emojiinfo/emojiinfo.py b/emojiinfo/emojiinfo.py index e464485..7413e6e 100644 --- a/emojiinfo/emojiinfo.py +++ b/emojiinfo/emojiinfo.py @@ -116,6 +116,7 @@ class EmojiInfo(commands.Cog): try: emoji: PartialEmoji = PartialEmoji.from_str(self, value=emoji) string, emoji_url, = await self.get_emoji_info(emoji) + self.logger.verbose(f"Emoji:\n{string}") except (IndexError, UnboundLocalError): return await ctx.send("Please provide a valid emoji!") From 7ed836a1cd8c82160823ca69a7260454e2fb1d63 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Sun, 19 May 2024 00:18:48 -0400 Subject: [PATCH 15/83] fix(seautils): pylint fixes --- seautils/seautils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 6790627..c575f6b 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -38,7 +38,7 @@ class SeaUtils(commands.Cog): ] return "\n".join(text) - def format_src(self, ctx: commands.Context, obj: Any) -> str: + def format_src(self, obj: Any) -> str: """A large portion of this code is repurposed from Zephyrkul's RTFS cog. https://github.com/Zephyrkul/FluffyCogs/blob/master/rtfs/rtfs.py""" obj = inspect.unwrap(obj) @@ -55,15 +55,15 @@ class SeaUtils(commands.Cog): @commands.command(aliases=["source", "src", "code", "showsource"]) @commands.is_owner() - async def showcode(self, ctx: commands.Context, *, object: str): + async def showcode(self, ctx: commands.Context, *, object: str): # pylint: disable=redefined-builtin """Show the code for a particular object.""" try: if object.startswith("/") and (obj := ctx.bot.tree.get_command(object[1:])): - text = self.format_src(ctx, obj) + text = self.format_src(obj) elif obj := ctx.bot.get_cog(object): - text = self.format_src(ctx, type(obj)) + text = self.format_src(type(obj)) elif obj := ctx.bot.get_command(object): - text = self.format_src(ctx, obj) + text = self.format_src(obj) temp_content = cf.pagify( text=cleanup_code(text), escape_mass_mentions=True, From 1405dae49e5ed8b66d7d483b4550350557bc3ef3 Mon Sep 17 00:00:00 2001 From: SeaswimmerTheFsh Date: Mon, 20 May 2024 20:59:01 -0400 Subject: [PATCH 16/83] fix(aurora): add roles to evidenceformat --- aurora/aurora.py | 20 +++++--------------- aurora/utilities/factory.py | 4 ++++ 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/aurora/aurora.py b/aurora/aurora.py index 15a9b2f..563a82c 100644 --- a/aurora/aurora.py +++ b/aurora/aurora.py @@ -19,8 +19,7 @@ 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.commands.converter import parse_relativedelta, parse_timedelta -from redbot.core.utils.chat_formatting import (box, error, humanize_list, - humanize_timedelta, warning) +from redbot.core.utils.chat_formatting import box, error, humanize_list, humanize_timedelta, warning from aurora.importers.aurora import ImportAuroraView from aurora.importers.galacticbot import ImportGalacticBotView @@ -29,19 +28,10 @@ from aurora.menus.guild import Guild from aurora.menus.immune import Immune from aurora.menus.overrides import Overrides from aurora.utilities.config import config, register_config -from aurora.utilities.database import (connect, create_guild_table, fetch_case, - mysql_log) -from aurora.utilities.factory import (addrole_embed, case_factory, - changes_factory, evidenceformat_factory, - guild_embed, immune_embed, - message_factory, overrides_embed) +from aurora.utilities.database import connect, create_guild_table, fetch_case, mysql_log +from aurora.utilities.factory import addrole_embed, case_factory, changes_factory, evidenceformat_factory, guild_embed, immune_embed, message_factory, overrides_embed from aurora.utilities.logger import logger -from aurora.utilities.utils import (check_moddable, check_permissions, - convert_timedelta_to_str, - fetch_channel_dict, fetch_user_dict, - generate_dict, get_footer_image, log, - send_evidenceformat, - timedelta_from_relativedelta) +from aurora.utilities.utils import check_moddable, check_permissions, convert_timedelta_to_str, fetch_channel_dict, fetch_user_dict, generate_dict, get_footer_image, log, send_evidenceformat, timedelta_from_relativedelta class Aurora(commands.Cog): @@ -50,7 +40,7 @@ class Aurora(commands.Cog): This cog stores all of its data in an SQLite database.""" __author__ = ["SeaswimmerTheFsh"] - __version__ = "2.1.2" + __version__ = "2.1.3" __documentation__ = "https://seacogs.coastalcommits.com/aurora/" async def red_delete_data_for_user(self, *, requester, user_id: int): diff --git a/aurora/utilities/factory.py b/aurora/utilities/factory.py index d7f4eb7..0d8a8cd 100644 --- a/aurora/utilities/factory.py +++ b/aurora/utilities/factory.py @@ -381,6 +381,10 @@ async def evidenceformat_factory(interaction: Interaction, case_dict: dict) -> s content = f"Case: {case_dict['moderation_id']:,} ({str.title(case_dict['moderation_type'])})\nTarget: {target_name} ({target_user['id']})\nModerator: {moderator_name} ({moderator_user['id']})" + if case_dict["role_id"] != "0": + role = interaction.guild.get_role(int(case_dict["role_id"])) + content += "\nRole: " + (role.name if role is not None else case_dict["role_id"]) + if case_dict["duration"] != "NULL": hours, minutes, seconds = map(int, case_dict["duration"].split(":")) td = timedelta(hours=hours, minutes=minutes, seconds=seconds) From ee9b62db5b8dc1aef4e6e5a198c84c546d724363 Mon Sep 17 00:00:00 2001 From: Sea Date: Thu, 23 May 2024 18:00:56 +0000 Subject: [PATCH 17/83] misc(repo): add index_name key to info.json --- info.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.json b/info.json index 04f29ab..816e30b 100644 --- a/info.json +++ b/info.json @@ -3,7 +3,7 @@ "SeaswimmerTheFsh (seasw.)" ], "install_msg": "Thanks for installing my repo!\n\nIf you have any issues with any of the cogs, please create an issue [here](https://coastalcommits.com/SeaswimmerTheFsh/SeaCogs/issues) or join my [Discord Server](https://discord.gg/eMUMe77Yb8 ).", - "name": "SeaCogs", + "index_name": "sea-cogs", "short": "Various cogs for Red, by SeaswimmerTheFsh (seasw.)", "description": "Various cogs for Red, by SeaswimmerTheFsh (seasw.)" } From 1a26d82c363c18ca7157a984139319594292bdfd Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 02:55:52 -0400 Subject: [PATCH 18/83] feat(logger): added the cog --- logger/__init__.py | 7 +++ logger/config.py | 106 +++++++++++++++++++++++++++++++++++++++++++++ logger/info.json | 17 ++++++++ logger/logger.py | 48 ++++++++++++++++++++ logger/menu.py | 30 +++++++++++++ 5 files changed, 208 insertions(+) create mode 100644 logger/__init__.py create mode 100644 logger/config.py create mode 100644 logger/info.json create mode 100644 logger/logger.py create mode 100644 logger/menu.py diff --git a/logger/__init__.py b/logger/__init__.py new file mode 100644 index 0000000..df5efcd --- /dev/null +++ b/logger/__init__.py @@ -0,0 +1,7 @@ +from redbot.core.bot import Red + +from .logger import Logger + + +async def setup(bot: Red) -> None: + await bot.add_cog(Logger(bot)) diff --git a/logger/config.py b/logger/config.py new file mode 100644 index 0000000..470cf99 --- /dev/null +++ b/logger/config.py @@ -0,0 +1,106 @@ +from redbot.core import Config + +config: Config = Config.get_conf(None, identifier=34236413658947743, cog_name="Logger", force_registration=True) + +def register_config(): + config.register_guild( + guild_update = False, + guild_update_channel = None, + channel_update = False, + channel_update_channel = None, + channel_delete = False, + channel_delete_channel = None, + overwrite_create = False, + overwrite_create_channel = None, + overwrite_update = False, + overwrite_update_channel = None, + overwrite_delete = False, + overwrite_delete_channel = None, + kick = False, + kick_channel = None, + member_prune = False, + member_prune_channel = None, + ban = False, + ban_channel = None, + unban = False, + unban_channel = None, + member_update = False, + member_update_channel = None, + member_role_update = False, + member_role_update_channel = None, + member_move = False, + member_move_channel = None, + member_disconnect = False, + member_disconnect_channel = None, + bot_add = False, + bot_add_channel = None, + role_create = False, + role_create_channel = None, + role_update = False, + role_update_channel = None, + role_delete = False, + role_delete_channel = None, + invite_create = False, + invite_create_channel = None, + invite_delete = False, + invite_delete_channel = None, + webhook_create = False, + webhook_create_channel = None, + webhook_update = False, + webhook_update_channel = None, + webhook_delete = False, + webhook_delete_channel = None, + emoji_create = False, + emoji_create_channel = None, + emoji_update = False, + emoji_update_channel = None, + emoji_delete = False, + emoji_delete_channel = None, + message_delete = False, + message_delete_channel = 967981200549494804, + message_edit = False, + message_edit_channel = 967981200549494804, + message_pin = False, + message_pin_channel = None, + message_unpin = False, + message_unpin_channel = None, + message_ignored_channels = [], + integration_create = False, + integration_create_channel = None, + integration_update = False, + integration_update_channel = None, + integration_delete = False, + integration_delete_channel = None, + stage_instance_create = False, + stage_instance_create_channel = None, + stage_instance_update = False, + stage_instance_update_channel = None, + stage_instance_delete = False, + stage_instance_delete_channel = None, + sticker_create = False, + sticker_create_channel = None, + sticker_update = False, + sticker_update_channel = None, + sticker_delete = False, + sticker_delete_channel = None, + scheduled_event_create = False, + scheduled_event_create_channel = None, + scheduled_event_update = False, + scheduled_event_update_channel = None, + scheduled_event_delete = False, + scheduled_event_delete_channel = None, + thread_create = False, + thread_create_channel = None, + thread_update = False, + thread_update_channel = None, + thread_delete = False, + thread_delete_channel = None, + app_command_permission_update = False, + app_command_permission_update_channel = None, + automod_rule_create = False, + automod_rule_create_channel = None, + automod_rule_update = False, + automod_rule_update_channel = None, + automod_rule_delete = False, + automod_rule_delete_channel = None, + ) diff --git a/logger/info.json b/logger/info.json new file mode 100644 index 0000000..42b8064 --- /dev/null +++ b/logger/info.json @@ -0,0 +1,17 @@ +{ + "author" : ["SeaswimmerTheFsh (seasw.)"], + "install_msg" : "Thank you for installing Logger!", + "name" : "Logger", + "short" : "Log events configurably.", + "description" : "Logger logs events to a channel of your choice. You can configure which events to log and which channel to log them to.", + "end_user_data_statement" : "This cog does not store end user data.", + "hidden": false, + "disabled": false, + "min_bot_version": "3.5.0", + "min_python_version": [3, 10, 0], + "tags": [ + "utility", + "moderation", + "logging" + ] + } diff --git a/logger/logger.py b/logger/logger.py new file mode 100644 index 0000000..a4be99c --- /dev/null +++ b/logger/logger.py @@ -0,0 +1,48 @@ +import time + +import discord +from redbot.core import commands +from redbot.core.bot import Red +from redbot.core.utils.chat_formatting import bold + +from .config import config, register_config + + +class Logger(commands.Cog): + def __init__(self, bot: Red) -> None: + self.bot: Red = bot + register_config() + + @commands.Cog.listener() + async def on_raw_message_delete(self, payload: discord.RawMessageDeleteEvent) -> None: + if not payload.guild_id: + return + + if self.bot.cog_disabled_in_guild(self, payload.guild_id): + return + + #if payload.channel_id in await config.guild(payload.guild_id).message_ignored_channels(): + #return + + if payload.cached_message: + if payload.cached_message.author.bot: + return + + if len(payload.cached_message.content) > 3898: + content = payload.cached_message.content[:3900] + "..." + else: + content = payload.cached_message.content + + author = payload.cached_message.author + + c = await config.guild(payload.guild_id).message_delete_channel() + if c: + channel = self.bot.get_channel(c) + if channel: + embed = discord.Embed(color=discord.Color.from_str(value="#ff470f")) + embed.set_author(name=f"{author.display_name} - Deleted Message", icon_url=author.display_avatar.url) + embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}") + content + embed.set_footer(text=f"Author: {author.id} | Message ID: {payload.message_id}") + embed.timestamp = time.time() + + await channel.send(embed=embed) diff --git a/logger/menu.py b/logger/menu.py new file mode 100644 index 0000000..b55a0eb --- /dev/null +++ b/logger/menu.py @@ -0,0 +1,30 @@ + +from discord import Embed, Message, ui +from redbot.core import commands + +from .config import config + + +async def get_config(ctx: commands.Context) -> dict: + return dict(sorted(await config.guild(ctx.guild).all().items())) + +async def get_embed(ctx: commands.Context, type: str = None): + conf = await get_config(ctx) + if not type or type not in conf.keys(): + embed = Embed( + title="Logger Configuration - Message Delete", + description="Please select a configuration option below.", + color=await ctx.embed_color(), + ) + + +class ConfigMenu(ui.View): + def __init__(self, ctx: commands.Context, message: Message, type: str = None, timeout: int = None): + super().__init__() + self.ctx = ctx + self.message = message + self.type = type + self.timeout = timeout + + async def on_timeout(self): + await self.message.edit(view=None) From 24703bb32fa9e7582a596afe4f40cb88ca722f34 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 03:01:04 -0400 Subject: [PATCH 19/83] fix(logger): awaited a coroutine --- logger/logger.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/logger/logger.py b/logger/logger.py index a4be99c..e990140 100644 --- a/logger/logger.py +++ b/logger/logger.py @@ -18,11 +18,11 @@ class Logger(commands.Cog): if not payload.guild_id: return - if self.bot.cog_disabled_in_guild(self, payload.guild_id): + if await self.bot.cog_disabled_in_guild(self, payload.guild_id): return - #if payload.channel_id in await config.guild(payload.guild_id).message_ignored_channels(): - #return + if payload.channel_id in await config.guild(payload.guild_id).message_ignored_channels(): + return if payload.cached_message: if payload.cached_message.author.bot: From 6fbd2531a867f75bc9ac3c1f7fd286be5feb0062 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 03:03:04 -0400 Subject: [PATCH 20/83] fix(logger): fixed some stuff --- logger/logger.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/logger/logger.py b/logger/logger.py index e990140..ce580a2 100644 --- a/logger/logger.py +++ b/logger/logger.py @@ -15,13 +15,17 @@ class Logger(commands.Cog): @commands.Cog.listener() async def on_raw_message_delete(self, payload: discord.RawMessageDeleteEvent) -> None: - if not payload.guild_id: + if payload.guild_id: + guild = self.bot.get_guild(payload.guild_id) + if guild is None: + return + else: return - if await self.bot.cog_disabled_in_guild(self, payload.guild_id): + if await self.bot.cog_disabled_in_guild(self, guild): return - if payload.channel_id in await config.guild(payload.guild_id).message_ignored_channels(): + if payload.channel_id in await config.guild(guild).message_ignored_channels(): return if payload.cached_message: @@ -35,7 +39,7 @@ class Logger(commands.Cog): author = payload.cached_message.author - c = await config.guild(payload.guild_id).message_delete_channel() + c = await config.guild(guild).message_delete_channel() if c: channel = self.bot.get_channel(c) if channel: From 0f82ddcf7b8d55cf8d5653dceb89fc236e35dcd9 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 03:04:40 -0400 Subject: [PATCH 21/83] fix(logger): fixed embed timestamp --- logger/logger.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/logger/logger.py b/logger/logger.py index ce580a2..9aaaf3d 100644 --- a/logger/logger.py +++ b/logger/logger.py @@ -1,4 +1,4 @@ -import time +from datetime import UTC, datetime import discord from redbot.core import commands @@ -43,10 +43,9 @@ class Logger(commands.Cog): if c: channel = self.bot.get_channel(c) if channel: - embed = discord.Embed(color=discord.Color.from_str(value="#ff470f")) + embed = discord.Embed(color=discord.Color.from_str(value="#ff470f"), timestamp=datetime.now(tz=UTC)) embed.set_author(name=f"{author.display_name} - Deleted Message", icon_url=author.display_avatar.url) embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}") + content embed.set_footer(text=f"Author: {author.id} | Message ID: {payload.message_id}") - embed.timestamp = time.time() await channel.send(embed=embed) From 0f1a9fb66c219b135c7e93f734747301745cf55f Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 03:05:55 -0400 Subject: [PATCH 22/83] fix(logger): added a missing newline --- logger/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logger/logger.py b/logger/logger.py index 9aaaf3d..f4ea0a4 100644 --- a/logger/logger.py +++ b/logger/logger.py @@ -45,7 +45,7 @@ class Logger(commands.Cog): if channel: embed = discord.Embed(color=discord.Color.from_str(value="#ff470f"), timestamp=datetime.now(tz=UTC)) embed.set_author(name=f"{author.display_name} - Deleted Message", icon_url=author.display_avatar.url) - embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}") + content + embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}\n") + content embed.set_footer(text=f"Author: {author.id} | Message ID: {payload.message_id}") await channel.send(embed=embed) From 7520ee783becb90723faf140cb7f935dc71855f4 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 03:07:12 -0400 Subject: [PATCH 23/83] fix(logger): hopefully fixed broken formatting --- logger/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logger/logger.py b/logger/logger.py index f4ea0a4..33b0038 100644 --- a/logger/logger.py +++ b/logger/logger.py @@ -45,7 +45,7 @@ class Logger(commands.Cog): if channel: embed = discord.Embed(color=discord.Color.from_str(value="#ff470f"), timestamp=datetime.now(tz=UTC)) embed.set_author(name=f"{author.display_name} - Deleted Message", icon_url=author.display_avatar.url) - embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}\n") + content + embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention} \n") + content embed.set_footer(text=f"Author: {author.id} | Message ID: {payload.message_id}") await channel.send(embed=embed) From ce502d5725622cf73142d4e02e18aca3252a4c42 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 03:08:39 -0400 Subject: [PATCH 24/83] fix(logger): don't escape mentions n shit --- logger/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logger/logger.py b/logger/logger.py index 33b0038..8c70246 100644 --- a/logger/logger.py +++ b/logger/logger.py @@ -45,7 +45,7 @@ class Logger(commands.Cog): if channel: embed = discord.Embed(color=discord.Color.from_str(value="#ff470f"), timestamp=datetime.now(tz=UTC)) embed.set_author(name=f"{author.display_name} - Deleted Message", icon_url=author.display_avatar.url) - embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention} \n") + content + embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}\n", escape_formatting=False) + content embed.set_footer(text=f"Author: {author.id} | Message ID: {payload.message_id}") await channel.send(embed=embed) From 6d0d45736d57bc211d98a8128bc9588992d44109 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 03:09:51 -0400 Subject: [PATCH 25/83] fix(logger): just include author username in the author field, also include the guild icon in the footer --- logger/logger.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logger/logger.py b/logger/logger.py index 8c70246..3effb8a 100644 --- a/logger/logger.py +++ b/logger/logger.py @@ -44,8 +44,8 @@ class Logger(commands.Cog): channel = self.bot.get_channel(c) if channel: embed = discord.Embed(color=discord.Color.from_str(value="#ff470f"), timestamp=datetime.now(tz=UTC)) - embed.set_author(name=f"{author.display_name} - Deleted Message", icon_url=author.display_avatar.url) + embed.set_author(name=f"{author.name}", icon_url=author.display_avatar.url) embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}\n", escape_formatting=False) + content - embed.set_footer(text=f"Author: {author.id} | Message ID: {payload.message_id}") + embed.set_footer(text=f"Author: {author.id} | Message ID: {payload.message_id}", icon_url=guild.icon.url) await channel.send(embed=embed) From 742d786babc1376ce39f64c3bb8c4a6bdb3c42f3 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 03:13:03 -0400 Subject: [PATCH 26/83] fix(logger): testing if there's a discord api error --- logger/logger.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/logger/logger.py b/logger/logger.py index 3effb8a..097be0a 100644 --- a/logger/logger.py +++ b/logger/logger.py @@ -32,10 +32,10 @@ class Logger(commands.Cog): if payload.cached_message.author.bot: return - if len(payload.cached_message.content) > 3898: - content = payload.cached_message.content[:3900] + "..." - else: - content = payload.cached_message.content + # if len(payload.cached_message.content) > 3898: + # content = payload.cached_message.content[:3900] + "..." + # else: + content = payload.cached_message.content author = payload.cached_message.author From c584fb60e2022d003ae6ac5c308a4463bbe22b1e Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 03:14:05 -0400 Subject: [PATCH 27/83] misc(logger): added some markdown formatting --- logger/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logger/logger.py b/logger/logger.py index 097be0a..b9ca4c9 100644 --- a/logger/logger.py +++ b/logger/logger.py @@ -45,7 +45,7 @@ class Logger(commands.Cog): if channel: embed = discord.Embed(color=discord.Color.from_str(value="#ff470f"), timestamp=datetime.now(tz=UTC)) embed.set_author(name=f"{author.name}", icon_url=author.display_avatar.url) - embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}\n", escape_formatting=False) + content + embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}\n>>>", escape_formatting=False) + content embed.set_footer(text=f"Author: {author.id} | Message ID: {payload.message_id}", icon_url=guild.icon.url) await channel.send(embed=embed) From 6e7171fc4820449dbd6632b29d6e283c3c1bfdf5 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 03:14:27 -0400 Subject: [PATCH 28/83] fix(logger): oops lmao --- logger/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logger/logger.py b/logger/logger.py index b9ca4c9..ad78f81 100644 --- a/logger/logger.py +++ b/logger/logger.py @@ -45,7 +45,7 @@ class Logger(commands.Cog): if channel: embed = discord.Embed(color=discord.Color.from_str(value="#ff470f"), timestamp=datetime.now(tz=UTC)) embed.set_author(name=f"{author.name}", icon_url=author.display_avatar.url) - embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}\n>>>", escape_formatting=False) + content + embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}\n>>> ", escape_formatting=False) + content embed.set_footer(text=f"Author: {author.id} | Message ID: {payload.message_id}", icon_url=guild.icon.url) await channel.send(embed=embed) From ce3193e113c909c5cda7ccb87a1df120140ac77b Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Fri, 24 May 2024 03:36:44 -0400 Subject: [PATCH 29/83] some changes or sm idk --- logger/logger.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/logger/logger.py b/logger/logger.py index ad78f81..e856aed 100644 --- a/logger/logger.py +++ b/logger/logger.py @@ -32,10 +32,7 @@ class Logger(commands.Cog): if payload.cached_message.author.bot: return - # if len(payload.cached_message.content) > 3898: - # content = payload.cached_message.content[:3900] + "..." - # else: - content = payload.cached_message.content + content = f">>> {payload.cached_message.content}" author = payload.cached_message.author @@ -45,7 +42,7 @@ class Logger(commands.Cog): if channel: embed = discord.Embed(color=discord.Color.from_str(value="#ff470f"), timestamp=datetime.now(tz=UTC)) embed.set_author(name=f"{author.name}", icon_url=author.display_avatar.url) - embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}\n>>> ", escape_formatting=False) + content + embed.description = bold(text=f"Message sent by {author.mention} deleted in {payload.cached_message.channel.mention}\n", escape_formatting=False) + content embed.set_footer(text=f"Author: {author.id} | Message ID: {payload.message_id}", icon_url=guild.icon.url) await channel.send(embed=embed) From e9c062afa951bef99b46c371f77652a92252e7d4 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 16:22:22 -0400 Subject: [PATCH 30/83] feat(seautils): added dig command --- seautils/seautils.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/seautils/seautils.py b/seautils/seautils.py index c575f6b..d2c42b3 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -5,6 +5,7 @@ # ____) | __/ (_| \__ \\ V V /| | | | | | | | | | | | __/ | # |_____/ \___|\__,_|___/ \_/\_/ |_|_| |_| |_|_| |_| |_|\___|_| +import asyncio import inspect import operator from functools import partial, partialmethod @@ -82,3 +83,22 @@ class SeaUtils(commands.Cog): await ctx.send(embed=embed, reference=ctx.message.to_reference(fail_if_not_exists=False)) else: await ctx.send(content="Object not found!", reference=ctx.message.to_reference(fail_if_not_exists=False)) + + @commands.command(name='dig', aliases=['dnslookup', 'nslookup']) + @commands.is_owner() + async def dig(self, ctx: commands.Context, name: str, type: str | None = 'A', server: str | None = None, port: int = 53) -> None: + """Retrieve DNS information for a domain.""" + command_opts: list[str | int] = ['dig'] + if server: + command_opts.extend(['@', server]) + command_opts.extend([name, type]) + if port != 53: + command_opts.extend(['-p', port]) + command_opts.extend(['+yaml']) + + process = await asyncio.create_subprocess_exec(*command_opts, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) + stdout, stderr = await process.communicate() + if stderr: + await ctx.send(content=cf.box(text=stderr.decode())) + else: + await ctx.send(content=cf.box(text=stdout.decode(), lang='yaml')) From 8867cc627f8c107f99fbcbace6a0ebcbd2e7b2ba Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 16:33:15 -0400 Subject: [PATCH 31/83] feat(seautils): add an embed to the dig command --- seautils/seautils.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index d2c42b3..15362a7 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -8,9 +8,11 @@ import asyncio import inspect import operator +from datetime import datetime from functools import partial, partialmethod from typing import Any +import yaml from discord import Embed, app_commands from discord.utils import CachedSlotProperty, cached_property from redbot.core import commands @@ -99,6 +101,31 @@ class SeaUtils(commands.Cog): process = await asyncio.create_subprocess_exec(*command_opts, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) stdout, stderr = await process.communicate() if stderr: - await ctx.send(content=cf.box(text=stderr.decode())) + await ctx.maybe_send_embed(content= "An error was encountered!\n" + cf.box(text=stderr.decode())) else: - await ctx.send(content=cf.box(text=stdout.decode(), lang='yaml')) + data = yaml.safe_load(stdout.decode()) + message_data = data[0]['message'] + response_data = message_data['response_message_data'] + timestamp = datetime.fromisoformat(message_data['response_time'].replace('Z', '+00:00')) + if ctx.embed_requested(): + embed = Embed( + title="DNS Query Result", + description=f"Query for {response_data['QUESTION_SECTION'][0]}", + color=await ctx.embed_color(), + timestamp=timestamp + ) + embed.add_field(name="Response Address", value=message_data['response_address'], inline=True) + embed.add_field(name="Response Port", value=message_data['response_port'], inline=True) + embed.add_field(name="Query Address", value=message_data['query_address'], inline=True) + embed.add_field(name="Query Port", value=message_data['query_port'], inline=True) + embed.add_field(name="Status", value=response_data['status'], inline=True) + embed.add_field(name="Flags", value=response_data['flags'], inline=True) + + question_section = "\n".join(response_data['QUESTION_SECTION']) + embed.add_field(name="Question Section", value=f"```{question_section}```", inline=False) + + answer_section = "\n".join(response_data['ANSWER_SECTION']) + embed.add_field(name="Answer Section", value=f"```{answer_section}```", inline=False) + await ctx.send(embed=embed) + else: + await ctx.send(content=cf.box(text=stdout, lang='yaml')) From 93f358cfad1e00fe2084a2a585c344fc46bda464 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 17:46:14 -0400 Subject: [PATCH 32/83] fix(seautils): fixed timestamp --- seautils/seautils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 15362a7..6eaafa7 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -8,7 +8,6 @@ import asyncio import inspect import operator -from datetime import datetime from functools import partial, partialmethod from typing import Any @@ -106,13 +105,12 @@ class SeaUtils(commands.Cog): data = yaml.safe_load(stdout.decode()) message_data = data[0]['message'] response_data = message_data['response_message_data'] - timestamp = datetime.fromisoformat(message_data['response_time'].replace('Z', '+00:00')) if ctx.embed_requested(): embed = Embed( title="DNS Query Result", description=f"Query for {response_data['QUESTION_SECTION'][0]}", color=await ctx.embed_color(), - timestamp=timestamp + timestamp=message_data['response_time'] ) embed.add_field(name="Response Address", value=message_data['response_address'], inline=True) embed.add_field(name="Response Port", value=message_data['response_port'], inline=True) From aa7e347a95a7993e5fee8f4797ae8d78eabc8412 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 17:48:00 -0400 Subject: [PATCH 33/83] fix(seautils): fix a keyerror --- seautils/seautils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 6eaafa7..198a748 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -108,7 +108,6 @@ class SeaUtils(commands.Cog): if ctx.embed_requested(): embed = Embed( title="DNS Query Result", - description=f"Query for {response_data['QUESTION_SECTION'][0]}", color=await ctx.embed_color(), timestamp=message_data['response_time'] ) @@ -122,8 +121,9 @@ class SeaUtils(commands.Cog): question_section = "\n".join(response_data['QUESTION_SECTION']) embed.add_field(name="Question Section", value=f"```{question_section}```", inline=False) - answer_section = "\n".join(response_data['ANSWER_SECTION']) - embed.add_field(name="Answer Section", value=f"```{answer_section}```", inline=False) + if 'ANSWER_SECTION' in response_data: + answer_section = "\n".join(response_data['ANSWER_SECTION']) + embed.add_field(name="Answer Section", value=f"```{answer_section}```", inline=False) await ctx.send(embed=embed) else: await ctx.send(content=cf.box(text=stdout, lang='yaml')) From 028cae9e99e2d60ccaa26d87bd1ad19f1f7fdf4b Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 17:53:58 -0400 Subject: [PATCH 34/83] feat(seautils): improve error code handling --- seautils/seautils.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 198a748..c884d08 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -12,7 +12,7 @@ from functools import partial, partialmethod from typing import Any import yaml -from discord import Embed, app_commands +from discord import Color, Embed, app_commands from discord.utils import CachedSlotProperty, cached_property from redbot.core import commands from redbot.core.bot import Red @@ -103,8 +103,8 @@ class SeaUtils(commands.Cog): await ctx.maybe_send_embed(content= "An error was encountered!\n" + cf.box(text=stderr.decode())) else: data = yaml.safe_load(stdout.decode()) - message_data = data[0]['message'] - response_data = message_data['response_message_data'] + message_data: dict = data[0]['message'] + response_data: dict = message_data['response_message_data'] if ctx.embed_requested(): embed = Embed( title="DNS Query Result", @@ -118,12 +118,23 @@ class SeaUtils(commands.Cog): embed.add_field(name="Status", value=response_data['status'], inline=True) embed.add_field(name="Flags", value=response_data['flags'], inline=True) + match response_data.get('status'): + case 'FORMERR', 'SERVFAIL', 'NXDOMAIN', 'NOTIMP', 'REFUSED': + embed.colour = Color.red() + embed.description = "Dig query did not return `NOERROR` status." + case _: + embed.colour = await ctx.embed_color() + question_section = "\n".join(response_data['QUESTION_SECTION']) embed.add_field(name="Question Section", value=f"```{question_section}```", inline=False) if 'ANSWER_SECTION' in response_data: answer_section = "\n".join(response_data['ANSWER_SECTION']) embed.add_field(name="Answer Section", value=f"```{answer_section}```", inline=False) + + if 'AUTHORITY_SECTION' in response_data: + authority_section = "\n".join(response_data['AUTHORITY_SECTION']) + embed.add_field(name="Authority Section", value=f"```{authority_section}```", inline=False) await ctx.send(embed=embed) else: await ctx.send(content=cf.box(text=stdout, lang='yaml')) From 8b68cb7530ab59d494f62952efb38589b762dca7 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 17:54:46 -0400 Subject: [PATCH 35/83] fix(seautils): don't use match and case --- seautils/seautils.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index c884d08..cf29811 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -118,12 +118,9 @@ class SeaUtils(commands.Cog): embed.add_field(name="Status", value=response_data['status'], inline=True) embed.add_field(name="Flags", value=response_data['flags'], inline=True) - match response_data.get('status'): - case 'FORMERR', 'SERVFAIL', 'NXDOMAIN', 'NOTIMP', 'REFUSED': - embed.colour = Color.red() - embed.description = "Dig query did not return `NOERROR` status." - case _: - embed.colour = await ctx.embed_color() + if response_data.get('status') != 'NOERROR': + embed.colour = Color.red() + embed.description = "Dig query did not return `NOERROR` status." question_section = "\n".join(response_data['QUESTION_SECTION']) embed.add_field(name="Question Section", value=f"```{question_section}```", inline=False) From 7a2ee0a655c005a89cbde8b14903469e4e9585dc Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 17:57:10 -0400 Subject: [PATCH 36/83] misc(seautils): added an error symbol to the failed dns query result message --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index cf29811..ad22a84 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -120,7 +120,7 @@ class SeaUtils(commands.Cog): if response_data.get('status') != 'NOERROR': embed.colour = Color.red() - embed.description = "Dig query did not return `NOERROR` status." + embed.description = cf.error("Dig query did not return `NOERROR` status.") question_section = "\n".join(response_data['QUESTION_SECTION']) embed.add_field(name="Question Section", value=f"```{question_section}```", inline=False) From d44424224584b5cfba84869dd3481b1aaafca8ec Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 18:01:35 -0400 Subject: [PATCH 37/83] fix(seautils): catch the error that is raised if dig is not installed on the system --- seautils/seautils.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index ad22a84..e68f3f3 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -8,6 +8,7 @@ import asyncio import inspect import operator +from asyncio.subprocess import Process from functools import partial, partialmethod from typing import Any @@ -97,8 +98,13 @@ class SeaUtils(commands.Cog): command_opts.extend(['-p', port]) command_opts.extend(['+yaml']) - process = await asyncio.create_subprocess_exec(*command_opts, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) - stdout, stderr = await process.communicate() + try: + process: Process = await asyncio.create_subprocess_exec(*command_opts, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) + stdout, stderr = await process.communicate() + except (FileNotFoundError): + await ctx.maybe_send_embed(content="The `dig` command is not installed on this system.") + return + if stderr: await ctx.maybe_send_embed(content= "An error was encountered!\n" + cf.box(text=stderr.decode())) else: From 091f4fe36d2171b7ac29f7ce565977f78e177f5c Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 18:02:17 -0400 Subject: [PATCH 38/83] fix(seautils): fixed maybe_send_message --- seautils/seautils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index e68f3f3..3a15c05 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -102,11 +102,11 @@ class SeaUtils(commands.Cog): process: Process = await asyncio.create_subprocess_exec(*command_opts, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) stdout, stderr = await process.communicate() except (FileNotFoundError): - await ctx.maybe_send_embed(content="The `dig` command is not installed on this system.") + await ctx.maybe_send_embed(message="The `dig` command is not installed on this system.") return if stderr: - await ctx.maybe_send_embed(content= "An error was encountered!\n" + cf.box(text=stderr.decode())) + await ctx.maybe_send_embed(message="An error was encountered!\n" + cf.box(text=stderr.decode())) else: data = yaml.safe_load(stdout.decode()) message_data: dict = data[0]['message'] From 25fdf7b402e35712b64fb86a7cc21d84a7149342 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 18:31:38 -0400 Subject: [PATCH 39/83] feat(seautils): default to nslookup if dig is not present --- seautils/seautils.py | 94 ++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 3a15c05..8ef8e1f 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -101,43 +101,59 @@ class SeaUtils(commands.Cog): try: process: Process = await asyncio.create_subprocess_exec(*command_opts, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) stdout, stderr = await process.communicate() - except (FileNotFoundError): - await ctx.maybe_send_embed(message="The `dig` command is not installed on this system.") - return - - if stderr: - await ctx.maybe_send_embed(message="An error was encountered!\n" + cf.box(text=stderr.decode())) - else: - data = yaml.safe_load(stdout.decode()) - message_data: dict = data[0]['message'] - response_data: dict = message_data['response_message_data'] - if ctx.embed_requested(): - embed = Embed( - title="DNS Query Result", - color=await ctx.embed_color(), - timestamp=message_data['response_time'] - ) - embed.add_field(name="Response Address", value=message_data['response_address'], inline=True) - embed.add_field(name="Response Port", value=message_data['response_port'], inline=True) - embed.add_field(name="Query Address", value=message_data['query_address'], inline=True) - embed.add_field(name="Query Port", value=message_data['query_port'], inline=True) - embed.add_field(name="Status", value=response_data['status'], inline=True) - embed.add_field(name="Flags", value=response_data['flags'], inline=True) - - if response_data.get('status') != 'NOERROR': - embed.colour = Color.red() - embed.description = cf.error("Dig query did not return `NOERROR` status.") - - question_section = "\n".join(response_data['QUESTION_SECTION']) - embed.add_field(name="Question Section", value=f"```{question_section}```", inline=False) - - if 'ANSWER_SECTION' in response_data: - answer_section = "\n".join(response_data['ANSWER_SECTION']) - embed.add_field(name="Answer Section", value=f"```{answer_section}```", inline=False) - - if 'AUTHORITY_SECTION' in response_data: - authority_section = "\n".join(response_data['AUTHORITY_SECTION']) - embed.add_field(name="Authority Section", value=f"```{authority_section}```", inline=False) - await ctx.send(embed=embed) + if stderr: + await ctx.maybe_send_embed(message="An error was encountered!\n" + cf.box(text=stderr.decode())) else: - await ctx.send(content=cf.box(text=stdout, lang='yaml')) + data = yaml.safe_load(stdout.decode()) + message_data: dict = data[0]['message'] + response_data: dict = message_data['response_message_data'] + if ctx.embed_requested(): + embed = Embed( + title="DNS Query Result", + color=await ctx.embed_color(), + timestamp=message_data['response_time'] + ) + embed.add_field(name="Response Address", value=message_data['response_address'], inline=True) + embed.add_field(name="Response Port", value=message_data['response_port'], inline=True) + embed.add_field(name="Query Address", value=message_data['query_address'], inline=True) + embed.add_field(name="Query Port", value=message_data['query_port'], inline=True) + embed.add_field(name="Status", value=response_data['status'], inline=True) + embed.add_field(name="Flags", value=response_data['flags'], inline=True) + + if response_data.get('status') != 'NOERROR': + embed.colour = Color.red() + embed.description = cf.error("Dig query did not return `NOERROR` status.") + + question_section = "\n".join(response_data['QUESTION_SECTION']) + embed.add_field(name="Question Section", value=f"```{question_section}```", inline=False) + + if 'ANSWER_SECTION' in response_data: + answer_section = "\n".join(response_data['ANSWER_SECTION']) + embed.add_field(name="Answer Section", value=f"```{answer_section}```", inline=False) + + if 'AUTHORITY_SECTION' in response_data: + authority_section = "\n".join(response_data['AUTHORITY_SECTION']) + embed.add_field(name="Authority Section", value=f"```{authority_section}```", inline=False) + await ctx.send(embed=embed) + else: + await ctx.send(content=cf.box(text=stdout, lang='yaml')) + except (FileNotFoundError): + try: + ns_process = await asyncio.create_subprocess_exec('nslookup', name, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) + ns_stdout, ns_stderr = await ns_process.communicate() + if ns_stderr: + await ctx.maybe_send_embed(message="An error was encountered!\n" + cf.box(text=ns_stderr.decode())) + else: + warning = cf.warning("`dig` is not installed! Defaulting to `nslookup`.\nThis command provides more information when `dig` is installed on the system.\n") + if await ctx.embed_requested(): + embed = Embed( + title="DNS Query Result", + color=await ctx.embed_color(), + timestamp=ctx.message.created_at + ) + embed.description = warning + cf.box(text=ns_stdout.decode()) + await ctx.send(embed=embed) + else: + await ctx.send(content= warning + cf.box(text=ns_stdout.decode())) + except (FileNotFoundError): + await ctx.maybe_send_embed(message=cf.error("Neither `dig` nor `nslookup` are installed on the system. Unable to resolve DNS query.")) From 7d51814a288b21a059a9ac8c98136887c161eb5f Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 18:35:17 -0400 Subject: [PATCH 40/83] misc(seautils): purposefully breaking dig so i can test nslookup fallback --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 8ef8e1f..005a0b1 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -90,7 +90,7 @@ class SeaUtils(commands.Cog): @commands.is_owner() async def dig(self, ctx: commands.Context, name: str, type: str | None = 'A', server: str | None = None, port: int = 53) -> None: """Retrieve DNS information for a domain.""" - command_opts: list[str | int] = ['dig'] + command_opts: list[str | int] = ['digsss'] if server: command_opts.extend(['@', server]) command_opts.extend([name, type]) From 5ffc42480abdb4dfaf7efc9e3e12a3ec33a419dd Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 18:40:43 -0400 Subject: [PATCH 41/83] fix(seautils): revert breaking dig --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 005a0b1..8ef8e1f 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -90,7 +90,7 @@ class SeaUtils(commands.Cog): @commands.is_owner() async def dig(self, ctx: commands.Context, name: str, type: str | None = 'A', server: str | None = None, port: int = 53) -> None: """Retrieve DNS information for a domain.""" - command_opts: list[str | int] = ['digsss'] + command_opts: list[str | int] = ['dig'] if server: command_opts.extend(['@', server]) command_opts.extend([name, type]) From 29bb64b35c194f08f548057e39df023e5ef199c8 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 18:42:42 -0400 Subject: [PATCH 42/83] fix(seautils): query ANY instead of A records --- seautils/seautils.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 8ef8e1f..c7e732f 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -88,15 +88,12 @@ class SeaUtils(commands.Cog): @commands.command(name='dig', aliases=['dnslookup', 'nslookup']) @commands.is_owner() - async def dig(self, ctx: commands.Context, name: str, type: str | None = 'A', server: str | None = None, port: int = 53) -> None: + async def dig(self, ctx: commands.Context, name: str, type: str | None = 'ANY', server: str | None = None, port: int = 53) -> None: """Retrieve DNS information for a domain.""" command_opts: list[str | int] = ['dig'] if server: command_opts.extend(['@', server]) - command_opts.extend([name, type]) - if port != 53: - command_opts.extend(['-p', port]) - command_opts.extend(['+yaml']) + command_opts.extend([name, type, '-p', port, '+yaml']) try: process: Process = await asyncio.create_subprocess_exec(*command_opts, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) From 54491cb9c9d19c492718c7c95dccb42d69de8d49 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 18:44:01 -0400 Subject: [PATCH 43/83] fix(seautils): convert port number to a string --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index c7e732f..85df38e 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -93,7 +93,7 @@ class SeaUtils(commands.Cog): command_opts: list[str | int] = ['dig'] if server: command_opts.extend(['@', server]) - command_opts.extend([name, type, '-p', port, '+yaml']) + command_opts.extend([name, type, '-p', str(port), '+yaml']) try: process: Process = await asyncio.create_subprocess_exec(*command_opts, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) From b27a3ee7788fb89ea571a73aecf2380189303d81 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 18:46:32 -0400 Subject: [PATCH 44/83] fix(seautils): fall back to the embed description if answer_section is too long --- seautils/seautils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 85df38e..ce9c64e 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -126,7 +126,10 @@ class SeaUtils(commands.Cog): if 'ANSWER_SECTION' in response_data: answer_section = "\n".join(response_data['ANSWER_SECTION']) - embed.add_field(name="Answer Section", value=f"```{answer_section}```", inline=False) + if len(answer_section) > 1024: + embed.description = answer_section + else: + embed.add_field(name="Answer Section", value=f"```{answer_section}```", inline=False) if 'AUTHORITY_SECTION' in response_data: authority_section = "\n".join(response_data['AUTHORITY_SECTION']) From fb468ee63e19e8f1dc7b8050a46eb05705ff2e0b Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 18:55:09 -0400 Subject: [PATCH 45/83] fix(seautils): retrieve A, AAAA, and CNAME records by default (& docstring changes) --- seautils/seautils.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index ce9c64e..1feb77a 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -88,12 +88,19 @@ class SeaUtils(commands.Cog): @commands.command(name='dig', aliases=['dnslookup', 'nslookup']) @commands.is_owner() - async def dig(self, ctx: commands.Context, name: str, type: str | None = 'ANY', server: str | None = None, port: int = 53) -> None: - """Retrieve DNS information for a domain.""" + async def dig(self, ctx: commands.Context, name: str, type: str | None = None, server: str | None = None, port: int = 53) -> None: + """Retrieve DNS information for a domain. + + Uses `dig` to perform a DNS query. Will fall back to `nslookup` if `dig` is not installed on the system. + `nslookup` does not provide as much information as `dig`, so only the `name` parameter will be used if `nslookup` is used. + Will return the A, AAAA, and CNAME records for a domain by default. You can specify a different record type with the `type` parameter.""" command_opts: list[str | int] = ['dig'] + query_types = [type] if type else ['A', 'AAAA', 'CNAME'] if server: command_opts.extend(['@', server]) - command_opts.extend([name, type, '-p', str(port), '+yaml']) + for query_type in query_types: + command_opts.extend([name, query_type]) + command_opts.extend(['-p', str(port), '+yaml']) try: process: Process = await asyncio.create_subprocess_exec(*command_opts, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) From 8608e6a34e3aa7517ef713ab9a53b690019a9d56 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 19:06:11 -0400 Subject: [PATCH 46/83] fix(seautils): fixed only the first A response being used --- seautils/seautils.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 1feb77a..2d44336 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -128,19 +128,33 @@ class SeaUtils(commands.Cog): embed.colour = Color.red() embed.description = cf.error("Dig query did not return `NOERROR` status.") - question_section = "\n".join(response_data['QUESTION_SECTION']) - embed.add_field(name="Question Section", value=f"```{question_section}```", inline=False) + questions = [] + answers = [] + authorities = [] + for m in data: + response = m['message']['response_message_data'] + if 'QUESTION_SECTION' in response: + for question in response['QUESTION_SECTION']: + questions.append(question) + if 'ANSWER_SECTION' in response: + for answer in response['ANSWER_SECTION']: + answers.append(answer) + if 'AUTHORITY_SECTION' in response: + for authority in response['AUTHORITY_SECTION']: + authorities.append(authority) - if 'ANSWER_SECTION' in response_data: - answer_section = "\n".join(response_data['ANSWER_SECTION']) - if len(answer_section) > 1024: - embed.description = answer_section - else: - embed.add_field(name="Answer Section", value=f"```{answer_section}```", inline=False) + question_section = "\n".join(questions) + embed.add_field(name="Question Section", value=f"{cf.box(question_section)}", inline=False) - if 'AUTHORITY_SECTION' in response_data: - authority_section = "\n".join(response_data['AUTHORITY_SECTION']) - embed.add_field(name="Authority Section", value=f"```{authority_section}```", inline=False) + answer_section = "\n".join(answers) + if len(answer_section) > 1024: + embed.description = cf.warning("Answer section is too long to fit within embed field, falling back to description.") + cf.box(answer_section) + else: + embed.add_field(name="Answer Section", value=f"{cf.box(answer_section)}", inline=False) + + if authorities: + authority_section = "\n".join(authorities) + embed.add_field(name="Authority Section", value=f"{cf.box(authority_section)}", inline=False) await ctx.send(embed=embed) else: await ctx.send(content=cf.box(text=stdout, lang='yaml')) From cb6ddabb4dfe506d959386d27762131cfbf23456 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 19:10:15 -0400 Subject: [PATCH 47/83] fix(seautils): prevent duplicates in dig --- seautils/seautils.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 2d44336..dedb4e3 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -135,13 +135,18 @@ class SeaUtils(commands.Cog): response = m['message']['response_message_data'] if 'QUESTION_SECTION' in response: for question in response['QUESTION_SECTION']: - questions.append(question) + if question not in questions: + questions.append(question) + if 'ANSWER_SECTION' in response: for answer in response['ANSWER_SECTION']: - answers.append(answer) + if answer not in answers: + answers.append(answer) + if 'AUTHORITY_SECTION' in response: for authority in response['AUTHORITY_SECTION']: - authorities.append(authority) + if authority not in authorities: + authorities.append(authority) question_section = "\n".join(questions) embed.add_field(name="Question Section", value=f"{cf.box(question_section)}", inline=False) From 7f46d6accc65d4597d0324c7cb86f358d3a38f7b Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 19:25:01 -0400 Subject: [PATCH 48/83] fix(seautils): fixed empty answer section --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index dedb4e3..69b80d0 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -157,7 +157,7 @@ class SeaUtils(commands.Cog): else: embed.add_field(name="Answer Section", value=f"{cf.box(answer_section)}", inline=False) - if authorities: + if not len(authorities) == 0: authority_section = "\n".join(authorities) embed.add_field(name="Authority Section", value=f"{cf.box(authority_section)}", inline=False) await ctx.send(embed=embed) From 50094b85fc7b322e35ac418fb277065cca1fe8f9 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 19:26:07 -0400 Subject: [PATCH 49/83] fix(seautils): fixed the wrong thing lmao --- seautils/seautils.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 69b80d0..8b87a70 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -148,16 +148,18 @@ class SeaUtils(commands.Cog): if authority not in authorities: authorities.append(authority) - question_section = "\n".join(questions) - embed.add_field(name="Question Section", value=f"{cf.box(question_section)}", inline=False) + if questions: + question_section = "\n".join(questions) + embed.add_field(name="Question Section", value=f"{cf.box(question_section)}", inline=False) - answer_section = "\n".join(answers) - if len(answer_section) > 1024: - embed.description = cf.warning("Answer section is too long to fit within embed field, falling back to description.") + cf.box(answer_section) - else: - embed.add_field(name="Answer Section", value=f"{cf.box(answer_section)}", inline=False) + if answers: + answer_section = "\n".join(answers) + if len(answer_section) > 1024: + embed.description = cf.warning("Answer section is too long to fit within embed field, falling back to description.") + cf.box(answer_section) + else: + embed.add_field(name="Answer Section", value=f"{cf.box(answer_section)}", inline=False) - if not len(authorities) == 0: + if authorities: authority_section = "\n".join(authorities) embed.add_field(name="Authority Section", value=f"{cf.box(authority_section)}", inline=False) await ctx.send(embed=embed) From 2886d5e80d5b8bf7aec20220461a13436eeac3a6 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 19:29:26 -0400 Subject: [PATCH 50/83] feat(seautils): use prolog syntax highlighting for dig results --- seautils/seautils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 8b87a70..da87b3a 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -150,18 +150,18 @@ class SeaUtils(commands.Cog): if questions: question_section = "\n".join(questions) - embed.add_field(name="Question Section", value=f"{cf.box(question_section)}", inline=False) + embed.add_field(name="Question Section", value=f"{cf.box(text=question_section, lang='prolog')}", inline=False) if answers: answer_section = "\n".join(answers) if len(answer_section) > 1024: embed.description = cf.warning("Answer section is too long to fit within embed field, falling back to description.") + cf.box(answer_section) else: - embed.add_field(name="Answer Section", value=f"{cf.box(answer_section)}", inline=False) + embed.add_field(name="Answer Section", value=f"{cf.box(text=answer_section, lang='prolog')}", inline=False) if authorities: authority_section = "\n".join(authorities) - embed.add_field(name="Authority Section", value=f"{cf.box(authority_section)}", inline=False) + embed.add_field(name="Authority Section", value=f"{cf.box(text=authority_section, lang='prolog')}", inline=False) await ctx.send(embed=embed) else: await ctx.send(content=cf.box(text=stdout, lang='yaml')) From a641cae640b31ada70a8248a28d2d9c00e229337 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 20:20:21 -0400 Subject: [PATCH 51/83] feat(seautils): add `[p]rfc` command --- poetry.lock | 34 +++++++++++++++++++++++++++++++++- pyproject.toml | 1 + seautils/info.json | 3 ++- seautils/seautils.py | 31 +++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 50be601..d30b1f7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -228,6 +228,27 @@ files = [ [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, +] + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] +html5lib = ["html5lib"] +lxml = ["lxml"] + [[package]] name = "brotli" version = "1.1.0" @@ -2111,6 +2132,17 @@ files = [ {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, ] +[[package]] +name = "soupsieve" +version = "2.5" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.8" +files = [ + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, +] + [[package]] name = "tinycss2" version = "1.2.1" @@ -2451,4 +2483,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.12" -content-hash = "0ac382e0399d9c23c5f89a0ffeb3aae056dc8b28e864b22f815c0e3eb34175bd" +content-hash = "55119c37c690ab197058ad091cb31bdf7c1c51ae62947e0026f4cddb423093d3" diff --git a/pyproject.toml b/pyproject.toml index 245364d..a2afb43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ websockets = "^12.0" pillow = "^10.3.0" numpy = "^1.26.4" colorthief = "^0.2.1" +beautifulsoup4 = "^4.12.3" [tool.poetry.group.dev] optional = true diff --git a/seautils/info.json b/seautils/info.json index f331eac..8e93f9d 100644 --- a/seautils/info.json +++ b/seautils/info.json @@ -8,5 +8,6 @@ "hidden": true, "disabled": false, "min_bot_version": "3.5.0", - "min_python_version": [3, 8, 0] + "min_python_version": [3, 8, 0], + "requirements": ["beautifulsoup4"] } diff --git a/seautils/seautils.py b/seautils/seautils.py index da87b3a..389ea71 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -12,7 +12,9 @@ from asyncio.subprocess import Process from functools import partial, partialmethod from typing import Any +import aiohttp import yaml +from bs4 import BeautifulSoup from discord import Color, Embed, app_commands from discord.utils import CachedSlotProperty, cached_property from redbot.core import commands @@ -185,3 +187,32 @@ class SeaUtils(commands.Cog): await ctx.send(content= warning + cf.box(text=ns_stdout.decode())) except (FileNotFoundError): await ctx.maybe_send_embed(message=cf.error("Neither `dig` nor `nslookup` are installed on the system. Unable to resolve DNS query.")) + + async def get_results(self, ctx: commands.Context, soup: BeautifulSoup) -> list: + pre_tags = soup.find_all('pre') + content = [] + for pre_tag in pre_tags: + if await ctx.embed_requested(): + embed = Embed( + title="RFC Document", + description=pre_tag.text, + color=await ctx.embed_color() + ) + content.append(embed) + else: + content.append(pre_tag.text) + return content + + @commands.command() + async def rfc(self, ctx: commands.Context, number: int) -> None: + """Retrieve the text of an RFC document.""" + url = f"https://www.rfc-editor.org/rfc/rfc{number}.html" + async with aiohttp.ClientSession() as session: + async with session.get(url=url) as response: + if response.status == 200: + html = await response.text() + soup = BeautifulSoup(html, 'html.parser') + content = await self.get_results(ctx, soup) + await SimpleMenu(pages=content, disable_after_timeout=True, timeout=300).start(ctx) + else: + await ctx.maybe_send_embed(content=cf.error(f"An error occurred while fetching RFC {number}. Status code: {response.status}.")) From 28246121a6ae55aa1000fc5354d8fd80b143b0aa Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 20:29:39 -0400 Subject: [PATCH 52/83] feat(seautils): use markdownify to convert rfc html documents to markdown --- poetry.lock | 17 ++++++++++++++++- pyproject.toml | 1 + seautils/info.json | 2 +- seautils/seautils.py | 32 ++++++++++++++++---------------- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/poetry.lock b/poetry.lock index d30b1f7..017d640 100644 --- a/poetry.lock +++ b/poetry.lock @@ -911,6 +911,21 @@ profiling = ["gprof2dot"] rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] +[[package]] +name = "markdownify" +version = "0.12.1" +description = "Convert HTML to markdown." +optional = false +python-versions = "*" +files = [ + {file = "markdownify-0.12.1-py3-none-any.whl", hash = "sha256:a3805abd8166dbb7b27783c5599d91f54f10d79894b2621404d85b333c7ce561"}, + {file = "markdownify-0.12.1.tar.gz", hash = "sha256:1fb08c618b30e0ee7a31a39b998f44a18fb28ab254f55f4af06b6d35a2179e27"}, +] + +[package.dependencies] +beautifulsoup4 = ">=4.9,<5" +six = ">=1.15,<2" + [[package]] name = "markupsafe" version = "2.1.5" @@ -2483,4 +2498,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.12" -content-hash = "55119c37c690ab197058ad091cb31bdf7c1c51ae62947e0026f4cddb423093d3" +content-hash = "229d7fd39618cf708f3cd5409dde2e6e25b822e4f936e14b3ade9800bf00daab" diff --git a/pyproject.toml b/pyproject.toml index a2afb43..872ccdf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,7 @@ pillow = "^10.3.0" numpy = "^1.26.4" colorthief = "^0.2.1" beautifulsoup4 = "^4.12.3" +markdownify = "^0.12.1" [tool.poetry.group.dev] optional = true diff --git a/seautils/info.json b/seautils/info.json index 8e93f9d..7356137 100644 --- a/seautils/info.json +++ b/seautils/info.json @@ -9,5 +9,5 @@ "disabled": false, "min_bot_version": "3.5.0", "min_python_version": [3, 8, 0], - "requirements": ["beautifulsoup4"] + "requirements": ["beautifulsoup4", "markdownify"] } diff --git a/seautils/seautils.py b/seautils/seautils.py index 389ea71..a32d02c 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -17,6 +17,7 @@ import yaml from bs4 import BeautifulSoup from discord import Color, Embed, app_commands from discord.utils import CachedSlotProperty, cached_property +from markdownify import MarkdownConverter from redbot.core import commands from redbot.core.bot import Red from redbot.core.dev_commands import cleanup_code @@ -24,6 +25,9 @@ from redbot.core.utils import chat_formatting as cf from redbot.core.utils.views import SimpleMenu +def md(soup: BeautifulSoup, **options) -> Any | str: + return MarkdownConverter(**options).convert_soup(soup) + class SeaUtils(commands.Cog): """A collection of random utilities.""" @@ -188,21 +192,6 @@ class SeaUtils(commands.Cog): except (FileNotFoundError): await ctx.maybe_send_embed(message=cf.error("Neither `dig` nor `nslookup` are installed on the system. Unable to resolve DNS query.")) - async def get_results(self, ctx: commands.Context, soup: BeautifulSoup) -> list: - pre_tags = soup.find_all('pre') - content = [] - for pre_tag in pre_tags: - if await ctx.embed_requested(): - embed = Embed( - title="RFC Document", - description=pre_tag.text, - color=await ctx.embed_color() - ) - content.append(embed) - else: - content.append(pre_tag.text) - return content - @commands.command() async def rfc(self, ctx: commands.Context, number: int) -> None: """Retrieve the text of an RFC document.""" @@ -212,7 +201,18 @@ class SeaUtils(commands.Cog): if response.status == 200: html = await response.text() soup = BeautifulSoup(html, 'html.parser') - content = await self.get_results(ctx, soup) + pre_tags = soup.find_all('pre') + content = [] + for pre_tag in pre_tags: + if await ctx.embed_requested(): + embed = Embed( + title="RFC Document", + description=md(pre_tag), + color=await ctx.embed_color() + ) + content.append(embed) + else: + content.append(md(pre_tag)) await SimpleMenu(pages=content, disable_after_timeout=True, timeout=300).start(ctx) else: await ctx.maybe_send_embed(content=cf.error(f"An error occurred while fetching RFC {number}. Status code: {response.status}.")) From 99cd13ccf114179f4a188018223cd57435330a76 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 20:35:25 -0400 Subject: [PATCH 53/83] feat(seautils): add correct formatting for masked links --- seautils/seautils.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index a32d02c..9200927 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -8,6 +8,7 @@ import asyncio import inspect import operator +import re from asyncio.subprocess import Process from functools import partial, partialmethod from typing import Any @@ -28,6 +29,9 @@ from redbot.core.utils.views import SimpleMenu def md(soup: BeautifulSoup, **options) -> Any | str: return MarkdownConverter(**options).convert_soup(soup) +def convert_rfc_references(text: str): + return re.sub(r"\(RFC\s(\d+)\)", r"(https://www.rfc-editor.org/rfc/rfc\1.html)", text) + class SeaUtils(commands.Cog): """A collection of random utilities.""" @@ -204,15 +208,16 @@ class SeaUtils(commands.Cog): pre_tags = soup.find_all('pre') content = [] for pre_tag in pre_tags: + text = convert_rfc_references(md(pre_tag)) if await ctx.embed_requested(): embed = Embed( title="RFC Document", - description=md(pre_tag), + description=text, color=await ctx.embed_color() ) content.append(embed) else: - content.append(md(pre_tag)) + content.append(text) await SimpleMenu(pages=content, disable_after_timeout=True, timeout=300).start(ctx) else: await ctx.maybe_send_embed(content=cf.error(f"An error occurred while fetching RFC {number}. Status code: {response.status}.")) From c4ef2a7d4b32024fe56abcdb5d78d1fe9cce0cbe Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 20:38:39 -0400 Subject: [PATCH 54/83] fix(seautils): fixed some broken regex --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 9200927..ac71d1c 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -30,7 +30,7 @@ def md(soup: BeautifulSoup, **options) -> Any | str: return MarkdownConverter(**options).convert_soup(soup) def convert_rfc_references(text: str): - return re.sub(r"\(RFC\s(\d+)\)", r"(https://www.rfc-editor.org/rfc/rfc\1.html)", text) + return re.sub(r"\(\.rfc\s(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) class SeaUtils(commands.Cog): """A collection of random utilities.""" From 29b6a2141a6f0bf6e143025ee10cc3e16346c561 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 20:39:19 -0400 Subject: [PATCH 55/83] fix(seautils): actually actually fixed incorrect regex --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index ac71d1c..51a896f 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -30,7 +30,7 @@ def md(soup: BeautifulSoup, **options) -> Any | str: return MarkdownConverter(**options).convert_soup(soup) def convert_rfc_references(text: str): - return re.sub(r"\(\.rfc\s(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) + return re.sub(r"\(\.\/rfc\s(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) class SeaUtils(commands.Cog): """A collection of random utilities.""" From 0ed96babdbf0be6b69b9ef9aea03d579e209ba7e Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 20:40:48 -0400 Subject: [PATCH 56/83] fix(seautils): ACTUALLY fixed broken regex --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 51a896f..f6943d1 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -30,7 +30,7 @@ def md(soup: BeautifulSoup, **options) -> Any | str: return MarkdownConverter(**options).convert_soup(soup) def convert_rfc_references(text: str): - return re.sub(r"\(\.\/rfc\s(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) + return re.sub(r"\(\.\/rfc(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) class SeaUtils(commands.Cog): """A collection of random utilities.""" From 42e209b54755768443605c71987069cd6278681d Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 21:10:28 -0400 Subject: [PATCH 57/83] misc(seautils): include the number of the rfc document in the embed --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index f6943d1..146384f 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -211,7 +211,7 @@ class SeaUtils(commands.Cog): text = convert_rfc_references(md(pre_tag)) if await ctx.embed_requested(): embed = Embed( - title="RFC Document", + title=f"RFC Document {number}", description=text, color=await ctx.embed_color() ) From 8d3f5c1d5facc078854894ae2fdd4bcd20c5d00a Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 21:16:10 -0400 Subject: [PATCH 58/83] fix(seautils): fix table of contents in rfc documents --- seautils/seautils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 146384f..649a875 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -29,8 +29,10 @@ from redbot.core.utils.views import SimpleMenu def md(soup: BeautifulSoup, **options) -> Any | str: return MarkdownConverter(**options).convert_soup(soup) -def convert_rfc_references(text: str): - return re.sub(r"\(\.\/rfc(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) +def convert_rfc_references(text: str, number: int) -> str: + one = re.sub(r"\(\.\/rfc(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) + two = re.sub(r"\((#(?:section|page)-\d+)\)", f"https://www.rfc-editor.org/rfc/rfc{number}.html\1", one) + return two class SeaUtils(commands.Cog): """A collection of random utilities.""" From 0ea80075f6cc2b55a76fc80fa688271c85611bd6 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 21:16:45 -0400 Subject: [PATCH 59/83] fix(seautils): fixed a missing argument --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 649a875..5ef5dda 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -210,7 +210,7 @@ class SeaUtils(commands.Cog): pre_tags = soup.find_all('pre') content = [] for pre_tag in pre_tags: - text = convert_rfc_references(md(pre_tag)) + text = convert_rfc_references(md(pre_tag), number) if await ctx.embed_requested(): embed = Embed( title=f"RFC Document {number}", From ae8d0d5db4f7c3dac6513742991b3d942b6ebf61 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 21:17:29 -0400 Subject: [PATCH 60/83] fix(seautils): added missing () --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 5ef5dda..638a01e 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -31,7 +31,7 @@ def md(soup: BeautifulSoup, **options) -> Any | str: def convert_rfc_references(text: str, number: int) -> str: one = re.sub(r"\(\.\/rfc(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) - two = re.sub(r"\((#(?:section|page)-\d+)\)", f"https://www.rfc-editor.org/rfc/rfc{number}.html\1", one) + two = re.sub(r"\((#(?:section|page)-\d+)\)", f"(https://www.rfc-editor.org/rfc/rfc{number}.html\1)", one) return two class SeaUtils(commands.Cog): From ac5d4df36b357a32edf75db721ba9b7839170d43 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 21:18:49 -0400 Subject: [PATCH 61/83] fix(seautils): fixed broken regex --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 638a01e..4db4bfc 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -31,7 +31,7 @@ def md(soup: BeautifulSoup, **options) -> Any | str: def convert_rfc_references(text: str, number: int) -> str: one = re.sub(r"\(\.\/rfc(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) - two = re.sub(r"\((#(?:section|page)-\d+)\)", f"(https://www.rfc-editor.org/rfc/rfc{number}.html\1)", one) + two = re.sub(r"\((#(?:section|page)-\d+(?:.\d+)?)\)", f"(https://www.rfc-editor.org/rfc/rfc{number}.html\1)", one) return two class SeaUtils(commands.Cog): From 861a03719bd8dd01db153f55fa5bf47c3a423b92 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 21:22:30 -0400 Subject: [PATCH 62/83] fix(seautils): added a bad solution to a stupid problem --- seautils/seautils.py | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 4db4bfc..fd6f25b 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -211,15 +211,35 @@ class SeaUtils(commands.Cog): content = [] for pre_tag in pre_tags: text = convert_rfc_references(md(pre_tag), number) - if await ctx.embed_requested(): - embed = Embed( - title=f"RFC Document {number}", - description=text, - color=await ctx.embed_color() - ) - content.append(embed) + if len(text) > 4096: + text1 = text[:4096] + text2 = text[4096:] + if await ctx.embed_requested(): + embed = Embed( + title=f"RFC Document {number}", + description=text1, + color=await ctx.embed_color() + ) + content.append(embed) + embed2 = Embed( + title=f"RFC Document {number}", + description=text2, + color=await ctx.embed_color() + ) + content.append(embed2) + else: + content.append(text1) + content.append(text2) else: - content.append(text) + if await ctx.embed_requested(): + embed = Embed( + title=f"RFC Document {number}", + description=text, + color=await ctx.embed_color() + ) + content.append(embed) + else: + content.append(text) await SimpleMenu(pages=content, disable_after_timeout=True, timeout=300).start(ctx) else: await ctx.maybe_send_embed(content=cf.error(f"An error occurred while fetching RFC {number}. Status code: {response.status}.")) From 2d895d16c9eaba1c56313a591f77859f7eb8d707 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 21:54:48 -0400 Subject: [PATCH 63/83] fix(seautils): fixed body error --- seautils/seautils.py | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index fd6f25b..6b2618a 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -208,28 +208,21 @@ class SeaUtils(commands.Cog): html = await response.text() soup = BeautifulSoup(html, 'html.parser') pre_tags = soup.find_all('pre') - content = [] + content: list[Embed | str] = [] for pre_tag in pre_tags: text = convert_rfc_references(md(pre_tag), number) if len(text) > 4096: - text1 = text[:4096] - text2 = text[4096:] - if await ctx.embed_requested(): - embed = Embed( - title=f"RFC Document {number}", - description=text1, - color=await ctx.embed_color() - ) - content.append(embed) - embed2 = Embed( - title=f"RFC Document {number}", - description=text2, - color=await ctx.embed_color() - ) - content.append(embed2) - else: - content.append(text1) - content.append(text2) + pagified_text = cf.pagify(text, delims=["\n\n"], page_length=4096) + for page in pagified_text: + if await ctx.embed_requested(): + embed = Embed( + title=f"RFC Document {number}", + description=page, + color=await ctx.embed_color() + ) + content.append(embed) + else: + content.append(page) else: if await ctx.embed_requested(): embed = Embed( @@ -240,6 +233,9 @@ class SeaUtils(commands.Cog): content.append(embed) else: content.append(text) + if await ctx.embed_requested(): + for embed in content: + embed.set_footer(text=f"Page {content.index(embed) + 1}/{len(content)}") await SimpleMenu(pages=content, disable_after_timeout=True, timeout=300).start(ctx) else: await ctx.maybe_send_embed(content=cf.error(f"An error occurred while fetching RFC {number}. Status code: {response.status}.")) From b9f0dbf98a5272d81e39c8c62788ccc47cda36dc Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 21:56:43 -0400 Subject: [PATCH 64/83] fix(seautils): removed big gap at the bottom of rfc embeds --- seautils/seautils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 6b2618a..b37bdd6 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -32,7 +32,8 @@ def md(soup: BeautifulSoup, **options) -> Any | str: def convert_rfc_references(text: str, number: int) -> str: one = re.sub(r"\(\.\/rfc(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) two = re.sub(r"\((#(?:section|page)-\d+(?:.\d+)?)\)", f"(https://www.rfc-editor.org/rfc/rfc{number}.html\1)", one) - return two + three: str = re.sub(r"\n{3,}", "\n\n", two) + return three class SeaUtils(commands.Cog): """A collection of random utilities.""" From 58245c621cfdc71cdab576de3177fb23b8019894 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 21:58:20 -0400 Subject: [PATCH 65/83] misc(seautils): changed a function name --- seautils/seautils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index b37bdd6..06e704e 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -29,7 +29,7 @@ from redbot.core.utils.views import SimpleMenu def md(soup: BeautifulSoup, **options) -> Any | str: return MarkdownConverter(**options).convert_soup(soup) -def convert_rfc_references(text: str, number: int) -> str: +def format_rfx_text(text: str, number: int) -> str: one = re.sub(r"\(\.\/rfc(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) two = re.sub(r"\((#(?:section|page)-\d+(?:.\d+)?)\)", f"(https://www.rfc-editor.org/rfc/rfc{number}.html\1)", one) three: str = re.sub(r"\n{3,}", "\n\n", two) @@ -211,7 +211,7 @@ class SeaUtils(commands.Cog): pre_tags = soup.find_all('pre') content: list[Embed | str] = [] for pre_tag in pre_tags: - text = convert_rfc_references(md(pre_tag), number) + text = format_rfx_text(md(pre_tag), number) if len(text) > 4096: pagified_text = cf.pagify(text, delims=["\n\n"], page_length=4096) for page in pagified_text: From 069ea800db9c71dd684290cadc52b81fe3e1c859 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 22:02:42 -0400 Subject: [PATCH 66/83] feat(seautils): added a detailed docstring to the rfc command --- seautils/seautils.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 06e704e..3281583 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -201,7 +201,18 @@ class SeaUtils(commands.Cog): @commands.command() async def rfc(self, ctx: commands.Context, number: int) -> None: - """Retrieve the text of an RFC document.""" + """Retrieve the text of an RFC document. + + This command uses the [RFC Editor website](https://www.rfc-editor.org/) to fetch the text of an RFC document. + `number` refers to the number of the RFC document you wish to retrieve. + Modified excerpt from the RFC Editor website: + >>> The RFC Series (ISSN 2070-1721) contains technical and organizational documents about the Internet, + including the specifications and policy documents produced by five streams: + - [Internet Engineering Task Force](https://www.ietf.org/) + - [Internet Research Task Force](https://www.irtf.org/) + - [Internet Architecture Board](https://www.iab.org/) + - [Independent Submissions](https://www.rfc-editor.org/independent) + - [Editorial](https://www.rfc-editor.org/info/rfc9280)""" url = f"https://www.rfc-editor.org/rfc/rfc{number}.html" async with aiohttp.ClientSession() as session: async with session.get(url=url) as response: From 7207cd374721fbb99a89831521a5666c8798097e Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 22:09:56 -0400 Subject: [PATCH 67/83] misc(seautils): improved the rfc docstring --- seautils/seautils.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 3281583..2084062 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -205,14 +205,10 @@ class SeaUtils(commands.Cog): This command uses the [RFC Editor website](https://www.rfc-editor.org/) to fetch the text of an RFC document. `number` refers to the number of the RFC document you wish to retrieve. - Modified excerpt from the RFC Editor website: - >>> The RFC Series (ISSN 2070-1721) contains technical and organizational documents about the Internet, - including the specifications and policy documents produced by five streams: - - [Internet Engineering Task Force](https://www.ietf.org/) - - [Internet Research Task Force](https://www.irtf.org/) - - [Internet Architecture Board](https://www.iab.org/) - - [Independent Submissions](https://www.rfc-editor.org/independent) - - [Editorial](https://www.rfc-editor.org/info/rfc9280)""" + Modified excerpt from [Wikipedia](https://en.wikipedia.org/wiki/Request_for_Comments): + >>> A Request for Comments (RFC) is a publication in a series from the principal technical development and standards-setting bodies for the [Internet](https://en.wikipedia.org/wiki/Internet), most prominently the [Internet Engineering Task Force](https://en.wikipedia.org/wiki/Internet_Engineering_Task_Force). + An RFC is authored by individuals or groups of engineers and [computer scientists](https://en.wikipedia.org/wiki/Computer_scientist) in the form of a [memorandum](https://en.wikipedia.org/wiki/Memorandum) describing methods, behaviors, research, or innovations applicable to the working of the Internet and Internet-connected systems. + It is submitted either for [peer review](https://en.wikipedia.org/wiki/Peer_review) or to convey new concepts, information, or, occasionally, engineering humor.""" # noqa: E501 url = f"https://www.rfc-editor.org/rfc/rfc{number}.html" async with aiohttp.ClientSession() as session: async with session.get(url=url) as response: From 4f25e3d0f3bfae987d4a5424dc745be1bd8964ed Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 22:11:11 -0400 Subject: [PATCH 68/83] fix(seautils): removed some text from the rfc docstring --- seautils/seautils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 2084062..30f7d12 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -204,7 +204,6 @@ class SeaUtils(commands.Cog): """Retrieve the text of an RFC document. This command uses the [RFC Editor website](https://www.rfc-editor.org/) to fetch the text of an RFC document. - `number` refers to the number of the RFC document you wish to retrieve. Modified excerpt from [Wikipedia](https://en.wikipedia.org/wiki/Request_for_Comments): >>> A Request for Comments (RFC) is a publication in a series from the principal technical development and standards-setting bodies for the [Internet](https://en.wikipedia.org/wiki/Internet), most prominently the [Internet Engineering Task Force](https://en.wikipedia.org/wiki/Internet_Engineering_Task_Force). An RFC is authored by individuals or groups of engineers and [computer scientists](https://en.wikipedia.org/wiki/Computer_scientist) in the form of a [memorandum](https://en.wikipedia.org/wiki/Memorandum) describing methods, behaviors, research, or innovations applicable to the working of the Internet and Internet-connected systems. From dfabac55f510a72ff7dd64c49485a1467a551b5a Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 22:13:18 -0400 Subject: [PATCH 69/83] misc(seautils): hopefully fixed `[p]rfc`'s help from overflowing into a second page --- seautils/seautils.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 30f7d12..73bcfae 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -204,10 +204,7 @@ class SeaUtils(commands.Cog): """Retrieve the text of an RFC document. This command uses the [RFC Editor website](https://www.rfc-editor.org/) to fetch the text of an RFC document. - Modified excerpt from [Wikipedia](https://en.wikipedia.org/wiki/Request_for_Comments): - >>> A Request for Comments (RFC) is a publication in a series from the principal technical development and standards-setting bodies for the [Internet](https://en.wikipedia.org/wiki/Internet), most prominently the [Internet Engineering Task Force](https://en.wikipedia.org/wiki/Internet_Engineering_Task_Force). - An RFC is authored by individuals or groups of engineers and [computer scientists](https://en.wikipedia.org/wiki/Computer_scientist) in the form of a [memorandum](https://en.wikipedia.org/wiki/Memorandum) describing methods, behaviors, research, or innovations applicable to the working of the Internet and Internet-connected systems. - It is submitted either for [peer review](https://en.wikipedia.org/wiki/Peer_review) or to convey new concepts, information, or, occasionally, engineering humor.""" # noqa: E501 + > A [Request for Comments (RFC)](https://en.wikipedia.org/wiki/Request_for_Comments) is a publication in a series from the principal technical development and standards-setting bodies for the [Internet](https://en.wikipedia.org/wiki/Internet), most prominently the [Internet Engineering Task Force](https://en.wikipedia.org/wiki/Internet_Engineering_Task_Force). An RFC is authored by individuals or groups of engineers and [computer scientists](https://en.wikipedia.org/wiki/Computer_scientist) in the form of a [memorandum](https://en.wikipedia.org/wiki/Memorandum) describing methods, behaviors, research, or innovations applicable to the working of the Internet and Internet-connected systems. It is submitted either for [peer review](https://en.wikipedia.org/wiki/Peer_review) or to convey new concepts, information, or, occasionally, engineering humor.""" # noqa: E501 url = f"https://www.rfc-editor.org/rfc/rfc{number}.html" async with aiohttp.ClientSession() as session: async with session.get(url=url) as response: From 8f492cd93776ce07f10e1b7a60c6c3624d620353 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 22:14:35 -0400 Subject: [PATCH 70/83] fix(seautils): hopefully actually fixed the docstring --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 73bcfae..09f451b 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -204,7 +204,7 @@ class SeaUtils(commands.Cog): """Retrieve the text of an RFC document. This command uses the [RFC Editor website](https://www.rfc-editor.org/) to fetch the text of an RFC document. - > A [Request for Comments (RFC)](https://en.wikipedia.org/wiki/Request_for_Comments) is a publication in a series from the principal technical development and standards-setting bodies for the [Internet](https://en.wikipedia.org/wiki/Internet), most prominently the [Internet Engineering Task Force](https://en.wikipedia.org/wiki/Internet_Engineering_Task_Force). An RFC is authored by individuals or groups of engineers and [computer scientists](https://en.wikipedia.org/wiki/Computer_scientist) in the form of a [memorandum](https://en.wikipedia.org/wiki/Memorandum) describing methods, behaviors, research, or innovations applicable to the working of the Internet and Internet-connected systems. It is submitted either for [peer review](https://en.wikipedia.org/wiki/Peer_review) or to convey new concepts, information, or, occasionally, engineering humor.""" # noqa: E501 + A [Request for Comments (RFC)](https://en.wikipedia.org/wiki/Request_for_Comments) is a publication in a series from the principal technical development and standards-setting bodies for the [Internet](https://en.wikipedia.org/wiki/Internet), most prominently the [Internet Engineering Task Force](https://en.wikipedia.org/wiki/Internet_Engineering_Task_Force). An RFC is authored by individuals or groups of engineers and [computer scientists](https://en.wikipedia.org/wiki/Computer_scientist) in the form of a [memorandum](https://en.wikipedia.org/wiki/Memorandum) describing methods, behaviors, research, or innovations applicable to the working of the Internet and Internet-connected systems. It is submitted either for [peer review](https://en.wikipedia.org/wiki/Peer_review) or to convey new concepts, information, or, occasionally, engineering humor.""" # noqa: E501 url = f"https://www.rfc-editor.org/rfc/rfc{number}.html" async with aiohttp.ClientSession() as session: async with session.get(url=url) as response: From 5b23f2f0fbd0cd10faa349e195cdad3391de7e6b Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 22:17:20 -0400 Subject: [PATCH 71/83] feat(seautils): add the url of the rfc document being retrieved to the embed --- seautils/seautils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/seautils/seautils.py b/seautils/seautils.py index 09f451b..cd8a3dd 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -221,6 +221,7 @@ class SeaUtils(commands.Cog): if await ctx.embed_requested(): embed = Embed( title=f"RFC Document {number}", + url=url, description=page, color=await ctx.embed_color() ) From f51329524ce08e79ead3e9d8889918c523a5a983 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 22:19:09 -0400 Subject: [PATCH 72/83] fix(seautils): oops lmao --- seautils/seautils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/seautils/seautils.py b/seautils/seautils.py index cd8a3dd..b3c9480 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -232,6 +232,7 @@ class SeaUtils(commands.Cog): if await ctx.embed_requested(): embed = Embed( title=f"RFC Document {number}", + url=url, description=text, color=await ctx.embed_color() ) From 037a26deb0c7c63a0bcce710c1eb5f87f39cc553 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 22:20:51 -0400 Subject: [PATCH 73/83] misc(seautils): switch to datatracker.ietf.org links for publicly facing urls --- seautils/seautils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index b3c9480..c4ff3d8 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -206,6 +206,7 @@ class SeaUtils(commands.Cog): This command uses the [RFC Editor website](https://www.rfc-editor.org/) to fetch the text of an RFC document. A [Request for Comments (RFC)](https://en.wikipedia.org/wiki/Request_for_Comments) is a publication in a series from the principal technical development and standards-setting bodies for the [Internet](https://en.wikipedia.org/wiki/Internet), most prominently the [Internet Engineering Task Force](https://en.wikipedia.org/wiki/Internet_Engineering_Task_Force). An RFC is authored by individuals or groups of engineers and [computer scientists](https://en.wikipedia.org/wiki/Computer_scientist) in the form of a [memorandum](https://en.wikipedia.org/wiki/Memorandum) describing methods, behaviors, research, or innovations applicable to the working of the Internet and Internet-connected systems. It is submitted either for [peer review](https://en.wikipedia.org/wiki/Peer_review) or to convey new concepts, information, or, occasionally, engineering humor.""" # noqa: E501 url = f"https://www.rfc-editor.org/rfc/rfc{number}.html" + datatracker_url = f"https://datatracker.ietf.org/doc/rfc{number}" async with aiohttp.ClientSession() as session: async with session.get(url=url) as response: if response.status == 200: @@ -221,7 +222,7 @@ class SeaUtils(commands.Cog): if await ctx.embed_requested(): embed = Embed( title=f"RFC Document {number}", - url=url, + url=datatracker_url, description=page, color=await ctx.embed_color() ) @@ -232,7 +233,7 @@ class SeaUtils(commands.Cog): if await ctx.embed_requested(): embed = Embed( title=f"RFC Document {number}", - url=url, + url=datatracker_url, description=text, color=await ctx.embed_color() ) From 545106d496f9f07a74209bc8755a0c88eeceed3e Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 22:25:47 -0400 Subject: [PATCH 74/83] fix(seautils): fixed a typo in a function name --- seautils/seautils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index c4ff3d8..76cc789 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -29,7 +29,7 @@ from redbot.core.utils.views import SimpleMenu def md(soup: BeautifulSoup, **options) -> Any | str: return MarkdownConverter(**options).convert_soup(soup) -def format_rfx_text(text: str, number: int) -> str: +def format_rfc_text(text: str, number: int) -> str: one = re.sub(r"\(\.\/rfc(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) two = re.sub(r"\((#(?:section|page)-\d+(?:.\d+)?)\)", f"(https://www.rfc-editor.org/rfc/rfc{number}.html\1)", one) three: str = re.sub(r"\n{3,}", "\n\n", two) @@ -215,7 +215,7 @@ class SeaUtils(commands.Cog): pre_tags = soup.find_all('pre') content: list[Embed | str] = [] for pre_tag in pre_tags: - text = format_rfx_text(md(pre_tag), number) + text = format_rfc_text(md(pre_tag), number) if len(text) > 4096: pagified_text = cf.pagify(text, delims=["\n\n"], page_length=4096) for page in pagified_text: From 46f189a297e9abed28831fa95537e033e27abdc1 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Thu, 30 May 2024 11:02:22 -0400 Subject: [PATCH 75/83] fix(seautils): pylint fix --- .forgejo/workflows/config/.pylintrc | 3 ++- seautils/seautils.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/config/.pylintrc b/.forgejo/workflows/config/.pylintrc index 2dd59c9..94010af 100644 --- a/.forgejo/workflows/config/.pylintrc +++ b/.forgejo/workflows/config/.pylintrc @@ -18,4 +18,5 @@ import-self, relative-beyond-top-level, too-many-instance-attributes, - duplicate-code + duplicate-code, + too-many-nested-blocks diff --git a/seautils/seautils.py b/seautils/seautils.py index 76cc789..56bc5d8 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -101,14 +101,14 @@ class SeaUtils(commands.Cog): @commands.command(name='dig', aliases=['dnslookup', 'nslookup']) @commands.is_owner() - async def dig(self, ctx: commands.Context, name: str, type: str | None = None, server: str | None = None, port: int = 53) -> None: + async def dig(self, ctx: commands.Context, name: str, record_type: str | None = None, server: str | None = None, port: int = 53) -> None: """Retrieve DNS information for a domain. Uses `dig` to perform a DNS query. Will fall back to `nslookup` if `dig` is not installed on the system. `nslookup` does not provide as much information as `dig`, so only the `name` parameter will be used if `nslookup` is used. Will return the A, AAAA, and CNAME records for a domain by default. You can specify a different record type with the `type` parameter.""" command_opts: list[str | int] = ['dig'] - query_types = [type] if type else ['A', 'AAAA', 'CNAME'] + query_types: list[str] = [record_type] if record_type else ['A', 'AAAA', 'CNAME'] if server: command_opts.extend(['@', server]) for query_type in query_types: From c06db07f0821a2f391c5b6208fa7ef9f3dd266e2 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Sat, 1 Jun 2024 15:02:08 -0400 Subject: [PATCH 76/83] misc(seautils): bunch of miscellaneous changes --- seautils/seautils.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 56bc5d8..7a4040c 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -30,8 +30,8 @@ def md(soup: BeautifulSoup, **options) -> Any | str: return MarkdownConverter(**options).convert_soup(soup) def format_rfc_text(text: str, number: int) -> str: - one = re.sub(r"\(\.\/rfc(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) - two = re.sub(r"\((#(?:section|page)-\d+(?:.\d+)?)\)", f"(https://www.rfc-editor.org/rfc/rfc{number}.html\1)", one) + one: str = re.sub(r"\(\.\/rfc(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) + two: str = re.sub(r"\((#(?:section|page)-\d+(?:.\d+)?)\)", f"(https://www.rfc-editor.org/rfc/rfc{number}.html\1)", one) three: str = re.sub(r"\n{3,}", "\n\n", two) return three @@ -41,23 +41,23 @@ class SeaUtils(commands.Cog): __author__ = ["SeaswimmerTheFsh"] __version__ = "1.0.0" - def __init__(self, bot: Red): + def __init__(self, bot: Red) -> None: self.bot = bot def format_help_for_context(self, ctx: commands.Context) -> str: - pre_processed = super().format_help_for_context(ctx) or "" + pre_processed = super().format_help_for_context(ctx=ctx) or "" n = "\n" if "\n\n" not in pre_processed else "" text = [ f"{pre_processed}{n}", f"Cog Version: **{self.__version__}**", - f"Author: {cf.humanize_list(self.__author__)}" + f"Author: {cf.humanize_list(items=self.__author__)}" ] return "\n".join(text) def format_src(self, obj: Any) -> str: """A large portion of this code is repurposed from Zephyrkul's RTFS cog. https://github.com/Zephyrkul/FluffyCogs/blob/master/rtfs/rtfs.py""" - obj = inspect.unwrap(obj) + obj = inspect.unwrap(func=obj) src: Any = getattr(obj, "__func__", obj) if isinstance(obj, (commands.Command, app_commands.Command)): src = obj.callback @@ -67,11 +67,11 @@ class SeaUtils(commands.Cog): src = obj.fget elif isinstance(obj, (cached_property, CachedSlotProperty)): src = obj.function - return inspect.getsource(src) + return inspect.getsource(object=src) @commands.command(aliases=["source", "src", "code", "showsource"]) @commands.is_owner() - async def showcode(self, ctx: commands.Context, *, object: str): # pylint: disable=redefined-builtin + async def showcode(self, ctx: commands.Context, *, object: str) -> None: # pylint: disable=redefined-builtin """Show the code for a particular object.""" try: if object.startswith("/") and (obj := ctx.bot.tree.get_command(object[1:])): @@ -195,7 +195,7 @@ class SeaUtils(commands.Cog): embed.description = warning + cf.box(text=ns_stdout.decode()) await ctx.send(embed=embed) else: - await ctx.send(content= warning + cf.box(text=ns_stdout.decode())) + await ctx.send(content = warning + cf.box(text=ns_stdout.decode())) except (FileNotFoundError): await ctx.maybe_send_embed(message=cf.error("Neither `dig` nor `nslookup` are installed on the system. Unable to resolve DNS query.")) From 66b933569be682381744fc67d82723a505e6519b Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Sat, 1 Jun 2024 15:03:23 -0400 Subject: [PATCH 77/83] misc(seautils): soup --- seautils/seautils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seautils/seautils.py b/seautils/seautils.py index 7a4040c..304fd70 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -27,7 +27,7 @@ from redbot.core.utils.views import SimpleMenu def md(soup: BeautifulSoup, **options) -> Any | str: - return MarkdownConverter(**options).convert_soup(soup) + return MarkdownConverter(**options).convert_soup(soup=soup) def format_rfc_text(text: str, number: int) -> str: one: str = re.sub(r"\(\.\/rfc(\d+)", r"(https://www.rfc-editor.org/rfc/rfc\1.html", text) From 2ac1dacd19af043ab643b325f83707328dc0273d Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Mon, 3 Jun 2024 01:10:00 -0400 Subject: [PATCH 78/83] fix(backup): added another error type caught by backup import, in the case where you didn't reply to a message or upload a file --- backup/backup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup/backup.py b/backup/backup.py index 7fe9b4d..6202e3a 100644 --- a/backup/backup.py +++ b/backup/backup.py @@ -100,7 +100,7 @@ class Backup(commands.Cog): except (json.JSONDecodeError, IndexError): try: export = json.loads(await ctx.message.reference.resolved.attachments[0].read()) - except (json.JSONDecodeError, IndexError): + except (json.JSONDecodeError, IndexError, AttributeError): await ctx.send(error("Please provide a valid JSON export file.")) return From 73547699620538f6f28106c2759b6a82cc0d8310 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 4 Jun 2024 12:16:01 -0400 Subject: [PATCH 79/83] fix(emojiinfo): pylint fix --- emojiinfo/model.py | 1 + 1 file changed, 1 insertion(+) diff --git a/emojiinfo/model.py b/emojiinfo/model.py index af457d1..cc8a468 100644 --- a/emojiinfo/model.py +++ b/emojiinfo/model.py @@ -81,6 +81,7 @@ class PartialEmoji(discord.PartialEmoji): with open(path, "r", encoding="UTF-8") as file: emojis: dict = json.load(file) emoji_aliases = [] + emoji_group = None for dict_name, group in emojis.items(): for k, v in group.items(): if v == value: From 28f814db564444c672857e1b82e52e3c44ff79fd Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 4 Jun 2024 12:16:09 -0400 Subject: [PATCH 80/83] fix(seautils): pylint fix --- seautils/seautils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/seautils/seautils.py b/seautils/seautils.py index 304fd70..3bbf5cf 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -80,6 +80,8 @@ class SeaUtils(commands.Cog): text = self.format_src(type(obj)) elif obj := ctx.bot.get_command(object): text = self.format_src(obj) + else: + raise AttributeError temp_content = cf.pagify( text=cleanup_code(text), escape_mass_mentions=True, From e3e96e5b842ba8bd3ee8a6da5786369b6d4f508a Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 11 Jun 2024 16:39:04 -0400 Subject: [PATCH 81/83] fix(workflow): changed meli token --- .forgejo/workflows/workflow.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/workflow.yaml b/.forgejo/workflows/workflow.yaml index f88c687..98b12fc 100644 --- a/.forgejo/workflows/workflow.yaml +++ b/.forgejo/workflows/workflow.yaml @@ -58,7 +58,7 @@ jobs: npx -p "@getmeli/cli" meli upload ./site \ --url "https://pages.coastalcommits.com" \ --site "${{ vars.MELI_SITE_ID }}" \ - --token "${{ secrets.MELI_SITE_SECRET }}" \ + --token "${{ secrets.MELI_SECRET }}" \ --release "$CI_ACTION_REF_NAME_SLUG/${{ env.GITHUB_SHA }}" \ --branch "$CI_ACTION_REF_NAME_SLUG" From 24239425c5a183348add69dc53fc08c5f6f9a821 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 11 Jun 2024 16:48:03 -0400 Subject: [PATCH 82/83] fix(workflows): missing -e argument --- .forgejo/workflows/workflow.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/workflow.yaml b/.forgejo/workflows/workflow.yaml index 98b12fc..baca6fb 100644 --- a/.forgejo/workflows/workflow.yaml +++ b/.forgejo/workflows/workflow.yaml @@ -53,7 +53,7 @@ jobs: unset GITHUB_TOKEN unset GITLAB_TOKEN - echo "${YELLOW}Deploying to ${BLUE}Meli ${YELLOW}on branch ${GREEN}$CI_ACTION_REF_NAME_SLUG${YELLOW}...\n" + echo -e "${YELLOW}Deploying to ${BLUE}Meli ${YELLOW}on branch ${GREEN}$CI_ACTION_REF_NAME_SLUG${YELLOW}...\n" npx -p "@getmeli/cli" meli upload ./site \ --url "https://pages.coastalcommits.com" \ @@ -62,7 +62,7 @@ jobs: --release "$CI_ACTION_REF_NAME_SLUG/${{ env.GITHUB_SHA }}" \ --branch "$CI_ACTION_REF_NAME_SLUG" - echo "\n${YELLOW}Deployed to ${BLUE}Meli ${YELLOW}on branch ${GREEN}$CI_ACTION_REF_NAME_SLUG${YELLOW}!" - echo "${GREEN}https://$CI_ACTION_REF_NAME_SLUG.seacogs.coastalcommits.com/" + echo -e "\n${YELLOW}Deployed to ${BLUE}Meli ${YELLOW}on branch ${GREEN}$CI_ACTION_REF_NAME_SLUG${YELLOW}!" + echo -e "${GREEN}https://$CI_ACTION_REF_NAME_SLUG.seacogs.coastalcommits.com/" env: GITEA_TOKEN: ${{ secrets.COASTALCOMMITSTOKEN }} From d173dd68a5c760ed77dcca6e33b79e855fff8d04 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 11 Jun 2024 16:50:15 -0400 Subject: [PATCH 83/83] fix(workflow): nvm --- .forgejo/workflows/workflow.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/workflow.yaml b/.forgejo/workflows/workflow.yaml index baca6fb..98b12fc 100644 --- a/.forgejo/workflows/workflow.yaml +++ b/.forgejo/workflows/workflow.yaml @@ -53,7 +53,7 @@ jobs: unset GITHUB_TOKEN unset GITLAB_TOKEN - echo -e "${YELLOW}Deploying to ${BLUE}Meli ${YELLOW}on branch ${GREEN}$CI_ACTION_REF_NAME_SLUG${YELLOW}...\n" + echo "${YELLOW}Deploying to ${BLUE}Meli ${YELLOW}on branch ${GREEN}$CI_ACTION_REF_NAME_SLUG${YELLOW}...\n" npx -p "@getmeli/cli" meli upload ./site \ --url "https://pages.coastalcommits.com" \ @@ -62,7 +62,7 @@ jobs: --release "$CI_ACTION_REF_NAME_SLUG/${{ env.GITHUB_SHA }}" \ --branch "$CI_ACTION_REF_NAME_SLUG" - echo -e "\n${YELLOW}Deployed to ${BLUE}Meli ${YELLOW}on branch ${GREEN}$CI_ACTION_REF_NAME_SLUG${YELLOW}!" - echo -e "${GREEN}https://$CI_ACTION_REF_NAME_SLUG.seacogs.coastalcommits.com/" + echo "\n${YELLOW}Deployed to ${BLUE}Meli ${YELLOW}on branch ${GREEN}$CI_ACTION_REF_NAME_SLUG${YELLOW}!" + echo "${GREEN}https://$CI_ACTION_REF_NAME_SLUG.seacogs.coastalcommits.com/" env: GITEA_TOKEN: ${{ secrets.COASTALCOMMITSTOKEN }}