From c130a4e115c52892495b7b6cc8945f67757782e8 Mon Sep 17 00:00:00 2001 From: Vioshim <63890837+Vioshim@users.noreply.github.com> Date: Sun, 28 Apr 2024 01:20:05 -0500 Subject: [PATCH] Implements transformers for params in queries --- cogs/rtfm_slash.py | 189 ++++++++++++++++++++++++--------------------- 1 file changed, 103 insertions(+), 86 deletions(-) diff --git a/cogs/rtfm_slash.py b/cogs/rtfm_slash.py index c1b7291..0b84a9b 100644 --- a/cogs/rtfm_slash.py +++ b/cogs/rtfm_slash.py @@ -1,16 +1,15 @@ from __future__ import annotations -import typing -from typing import TYPE_CHECKING import os +from typing import TYPE_CHECKING, Optional -from discord.app_commands import AppCommandError, Choice -from discord.app_commands import command as app_command -import discord -from discord.ext import commands from discord import app_commands -from utils import fuzzy +from discord.app_commands import Choice, Transform, Transformer +from discord.ext import commands + import utils +from utils import fuzzy +from utils.extra import RtfmObject if TYPE_CHECKING: from discord import Interaction @@ -20,51 +19,103 @@ RTFMBot = commands.Bot -class RTFMSlash(commands.Cog): - def __init__(self, bot: RTFMBot) -> None: - self.bot = bot +class LibraryTransformer(Transformer): + async def transform(self, interaction: Interaction[RTFMBot], value: str) -> str: + return interaction.client.rtfm_libraries.get(value, value) + + async def autocomplete(self, interaction: Interaction[RTFMBot], current: str) -> list[Choice]: + choices = [Choice(name=name, value=name) for name in interaction.client.rtfm_libraries] + start_with = list(filter(lambda x: x.name.startswith(current), choices)) or choices + return start_with[:25] + + +class QueryTransformer(Transformer): + async def transform(self, interaction: Interaction[RTFMBot], value: str) -> RtfmObject: + library = interaction.client.rtfm_libraries.get(interaction.namespace.library, interaction.namespace.library) + library = library or "https://discord.com/developers/docs/" + unfiltered_results = await utils.rtfm(interaction.client, library) + if item := fuzzy.find(value, unfiltered_results, key=lambda t: t.name): + return item + + raise commands.BadArgument("No Results Found") + + async def autocomplete(self, interaction: Interaction[RTFMBot], current: str) -> list[Choice]: + library = interaction.client.rtfm_libraries.get(interaction.namespace.library, interaction.namespace.library) + library = library or "https://discord.com/developers/docs/" + unfiltered_results = await utils.rtfm(interaction.client, library) + choices = [ + Choice(name=result.name, value=result.name) + for result in fuzzy.finder(current, unfiltered_results, key=lambda t: t.name) + ] + return choices[:25] + + +class DocsQueryTransformer(Transformer): + async def transform(self, interaction: Interaction[RTFMBot], value: str) -> RtfmObject: + unfiltered_results = await utils.algolia_lookup( + interaction.client, + os.environ["ALGOLIA_APP_ID"], + os.environ["ALGOLIA_API_KEY"], + "discord", + value, + ) - @app_commands.user_install() - @app_commands.allow_contexts(guilds=True, dms=True, private_channels=True) - @app_commands.command(description="looks up docs", name="rtfm") - async def rtfm_slash( - self, interaction: discord.Interaction, library: typing.Optional[str] = None, query: typing.Optional[str] = None - ) -> None: - """Looks up docs for a library with optionally a query.""" + if result := fuzzy.find(value, unfiltered_results, key=lambda t: t.name): + return result + + raise commands.BadArgument("No Results Found") - library = library or self.bot.rtfm_libraries["master"] + async def autocomplete(self, interaction: Interaction[RTFMBot], current: str) -> list[Choice]: + unfiltered_results = await utils.algolia_lookup( + interaction.client, + os.environ["ALGOLIA_APP_ID"], + os.environ["ALGOLIA_API_KEY"], + "discord", + current, + ) + # use new method to handle results from discord ologia, but fuzzy can be used now + # I will remove the starting discord api docs if necessary. - if query is None or query == "No Results Found": - return await interaction.response.send_message(f"Alright Let's see \n{library}") + all_choices = [Choice(name=result.name, value=result.name) for result in unfiltered_results] - await interaction.response.send_message(f"Alright Let's see \n{library+query}") + if not current: + return all_choices[:25] - @rtfm_slash.autocomplete("library") - async def rtfm_library_autocomplete(self, interaction: discord.Interaction, current: str) -> list[Choice]: - libraries = self.bot.rtfm_libraries + filtered_results = fuzzy.finder(current, unfiltered_results, key=lambda t: t.name) - all_choices: list[Choice] = [Choice(name=name, value=link) for name, link in libraries.items()] - startswith: list[Choice] = [choices for choices in all_choices if choices.name.startswith(current)] - if not (current and startswith): - return all_choices[0:25] + results = [Choice(name=result.name, value=result.name) for result in filtered_results] - return startswith[0:25] + if not results: + results = [Choice(name="Getting Started", value="Getting Started")] - @rtfm_slash.autocomplete("query") - async def rtfm_query_autocomplete(self, interaction: discord.Interaction, current: str) -> list[Choice]: - url = interaction.namespace.library or self.bot.rtfm_libraries["master"] - unfiltered_results = await utils.rtfm(self.bot, url) + return results[:25] - all_choices = [Choice(name=result.name, value=result.url.removeprefix(url)) for result in unfiltered_results] - if not current: - return all_choices[:25] +Library = Transform[str, LibraryTransformer] +Query = Transform[RtfmObject, QueryTransformer] +DocsQuery = Transform[RtfmObject, DocsQueryTransformer] - filtered_results = fuzzy.finder(current, unfiltered_results, key=lambda t: t[0]) - results = [Choice(name=result.name, value=result.url.removeprefix(url)) for result in filtered_results] - return results[:25] +class RTFMSlash(commands.Cog): + def __init__(self, bot: RTFMBot) -> None: + self.bot = bot + + @app_commands.command(name="rtfm") + @app_commands.user_install() + @app_commands.allow_contexts(guilds=True, dms=True, private_channels=True) + async def rtfm_slash(self, interaction: Interaction[RTFMBot], library: Library, query: Optional[Query]) -> None: + """Looks up docs for a library with optionally a query. + + Parameters + ---------- + library : str + The library to search for. + query : RtfmObject + The query to search for. + """ + url = query.url if query else library + await interaction.response.send_message(f"Alright Let's see \n{url}") @rtfm_slash.error async def rtfm_error(self, interaction: discord.Interaction, error) -> None: @@ -72,50 +123,18 @@ async def rtfm_error(self, interaction: discord.Interaction, error) -> None: print(error) print(interaction.command) + @app_commands.command() @app_commands.user_install() @app_commands.allow_contexts(guilds=True, dms=True, private_channels=True) - @app_commands.command(description="looks up docs from discord developer docs", name="docs") - async def docs( - self, interaction: discord.Interaction, query: typing.Optional[str] = None - ) -> None: - """Looks up docs from discord developer docs with optionally a query.""" - - url = "https://discord.com/developers/docs/" - if query is None or query == "No Results Found": - # place holder for now. - return await interaction.response.send_message(f"Alright Let's see \n{url}") - - await interaction.response.send_message(f"Alright Let's see \n{url+query}") - - @docs.autocomplete("query") - async def docs_autocomplete(self, interaction: discord.Interaction, current: str) -> list[Choice]: - - url = "https://discord.com/developers/docs/" - - unfiltered_results = await utils.algolia_lookup(self.bot, os.environ["ALGOLIA_APP_ID"], os.environ["ALGOLIA_API_KEY"], "discord", current) - # use new method to handle results from discord ologia, but fuzzy can be used now - # I will remove the starting discord api docs if necessary. - - all_choices = [Choice(name=result.name, value=result.url.removeprefix(url)) for result in unfiltered_results] + async def docs(self, interaction: Interaction[RTFMBot], query: DocsQuery): + """Looks up docs from discord developer docs with optionally a query. - if not current: - return all_choices[:25] - - filtered_results = fuzzy.finder(current, unfiltered_results, key=lambda t: t[0]) - - results = [Choice(name=result.name, value=result.url.removeprefix(url)) for result in filtered_results] - - for result in results: - if len(result.value) > 100: - print(result.value) - - # seems to have issues with some sizes. - - if not results: - result = utils.RtfmObject("Getting Started", "https://discord.com/developers/docs/") - results = [Choice(name=result.name, value=result.url.removeprefix(url))] - - return results[:25] + Parameters + ---------- + query : RtfmObject + The query to search for. + """ + await interaction.response.send_message(f"Alright Let's see \n{query.url}") @docs.error async def docs_error(self, interaction: discord.Interaction, error) -> None: @@ -123,11 +142,11 @@ async def docs_error(self, interaction: discord.Interaction, error) -> None: print(error) print(interaction.command) + @app_commands.command() @app_commands.user_install() @app_commands.allow_contexts(guilds=True, dms=True, private_channels=True) - @app_commands.command(description="sends link to bot's source code", name="source") - async def source(self, interaction: discord.Interaction): - + async def source(self, interaction: Interaction[RTFMBot]): + """Sends link to the bot's source code""" view = discord.ui.View() view.add_item( discord.ui.Button( @@ -136,9 +155,7 @@ async def source(self, interaction: discord.Interaction): style=discord.ButtonStyle.link, ) ) - await interaction.response.send_message( - "Source: https://github.com/JDsProjects/Rtfm-Bot", view=view - ) + await interaction.response.send_message("Source: https://github.com/JDsProjects/Rtfm-Bot", view=view) async def setup(bot: RTFMBot) -> None: await bot.add_cog(RTFMSlash(bot))