From e03a7f103b9a0684b46cf5db6bf5888dd3a6feac Mon Sep 17 00:00:00 2001 From: Stephan K <55259393+skruglov2023@users.noreply.github.com> Date: Mon, 31 Mar 2025 00:48:40 -0500 Subject: [PATCH 1/5] @j5155 had a small idea, then I made it. ftc search now displays the first 5 teams that ftcscout presents, with options to then further choose to display the ftc command for a chosen team --- dozer/cogs/ftc.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/dozer/cogs/ftc.py b/dozer/cogs/ftc.py index 440c42e1..41d8496d 100755 --- a/dozer/cogs/ftc.py +++ b/dozer/cogs/ftc.py @@ -1,5 +1,5 @@ """Provides commands that pull information from The Orange Alliance, an FTC info API.""" - +import asyncio import json from asyncio import sleep from datetime import datetime @@ -283,6 +283,62 @@ async def team(self, ctx: DozerContext, team_num: int): await ctx.send(embed=e) + + @ftc.command(aliases=["teamsearch", "ftcsearch", "search"]) + @bot_has_permissions(embed_links=True) + @app_commands.describe(team_name="The name of the team you're interested in searching for") + async def searchteam(self, ctx: DozerContext,*, team_name: str): + """Search for an FTC team by name.""" + if team_name.isdigit(): + await self.team.callback(self, ctx, int(team_name)) + return + if len(team_name) < 3: + await ctx.send("Please provide a longer team name to search for.") + return + res = await self.scparser.req(f"teams/search?limit=5&searchText={urlquote(team_name)}") + async with res: + if res.status == 404: + await ctx.send("No teams found with that name!") + return + team_data = await res.json(content_type=None) + if len(team_data) == 1: + await self.team.callback(self, ctx, team_data[0]['number']) + return + manyteams = False + if len(team_data) > 5: # funny thing, ?limit doesn't work, confirmed with ftcscout devs, so we do it ourselves + team_data = team_data[:5] + manyteams = True + if not team_data: + await ctx.send(f"FTCScout returned nothing on request with HTTP response code {res.status}.") + return + + e = discord.Embed(color=embed_color, title=f"FTC Team Search: {team_name}") + for team in team_data: + e.add_field(name = f"Team {team['number']}", value = team['name'], inline = False) + + e.set_footer(text = "Team information from FTCScout") + + view = discord.ui.View() + + for team in team_data: + button = discord.ui.Button(label = f"Team {team['number']}", style = discord.ButtonStyle.primary) + button.callback = self.create_team_callback(ctx, team['number']) + view.add_item(button) + + if manyteams: + e.description = "More than 5 teams were found. If the team you want is not in this list, please refine your search" + e.set_footer(text="Team information from FTCScout") + message = await ctx.reply(embed = e, view = view, ephemeral = True, mention_author = False) + + await asyncio.sleep(180) # 3 minutes + for item in view.children: + item.disabled = True + await message.edit(view=view) + + searchteam.example_usage = """ + `{prefix}ftc search warbots` - show first 5 teams with "warbots" in their name + """ + @command() @bot_has_permissions(embed_links=True) @@ -459,6 +515,14 @@ async def matches(self, ctx: DozerContext, team_num: int, event_name: str = "lat """ + def create_team_callback(self, ctx, team_num): + async def callback(interaction): + await self.team.callback(self, ctx, team_num) + await interaction.response.defer() + + return callback + + async def setup(bot): """Adds the FTC information cog to the bot.""" await bot.add_cog(FTCInfo(bot)) From 25491d12421d3d61e679934e20dda5e7eb72c9f0 Mon Sep 17 00:00:00 2001 From: Stephan K <55259393+skruglov2023@users.noreply.github.com> Date: Mon, 31 Mar 2025 01:01:53 -0500 Subject: [PATCH 2/5] Oops some lint and I guess I forgot to import something that's been in use on dozer2 forever now --- dozer/cogs/ftc.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dozer/cogs/ftc.py b/dozer/cogs/ftc.py index 41d8496d..dc11d56c 100755 --- a/dozer/cogs/ftc.py +++ b/dozer/cogs/ftc.py @@ -6,6 +6,8 @@ from urllib.parse import urljoin, urlencode import base64 +from urllib.parse import quote as urlquote, urljoin + import aiohttp import async_timeout import discord @@ -516,6 +518,7 @@ async def matches(self, ctx: DozerContext, team_num: int, event_name: str = "lat def create_team_callback(self, ctx, team_num): + """Creates a callback for the search interaction buttons""" async def callback(interaction): await self.team.callback(self, ctx, team_num) await interaction.response.defer() From 7803cb482597662e58cb5a65fe7d6018d487395a Mon Sep 17 00:00:00 2001 From: Stephan K <55259393+skruglov2023@users.noreply.github.com> Date: Mon, 31 Mar 2025 01:05:10 -0500 Subject: [PATCH 3/5] more lint issues --- dozer/cogs/ftc.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dozer/cogs/ftc.py b/dozer/cogs/ftc.py index dc11d56c..34071960 100755 --- a/dozer/cogs/ftc.py +++ b/dozer/cogs/ftc.py @@ -3,11 +3,9 @@ import json from asyncio import sleep from datetime import datetime -from urllib.parse import urljoin, urlencode +from urllib.parse import urljoin, urlencode, quote as urlquote import base64 -from urllib.parse import quote as urlquote, urljoin - import aiohttp import async_timeout import discord From 81a1cbcaa601fe139183ba36f29524da0256991f Mon Sep 17 00:00:00 2001 From: Stephan K <55259393+skruglov2023@users.noreply.github.com> Date: Mon, 31 Mar 2025 01:55:51 -0500 Subject: [PATCH 4/5] Just realized it'd be great to make search the default for &ftc for a more seamless user experience --- dozer/cogs/ftc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dozer/cogs/ftc.py b/dozer/cogs/ftc.py index 34071960..e9eace20 100755 --- a/dozer/cogs/ftc.py +++ b/dozer/cogs/ftc.py @@ -232,12 +232,12 @@ def __init__(self, bot: commands.Bot): self.scparser = ScoutParser(self.http_session) @group(invoke_without_command=True, aliases=["ftcteam", "toa", "toateam", "ftcteaminfo"]) - async def ftc(self, ctx: DozerContext, team_num: int): + async def ftc(self, ctx: DozerContext, *, team_name: str): """ Get information on an FTC team from FTC-Events. If no subcommand is specified, the `team` subcommand is inferred, and the argument is taken as a team number. """ - await self.team.callback(self, ctx, team_num) # This works but Pylint throws an error + await self.searchteam.callback(self, ctx, team_name) # This works but Pylint throws an error ftc.example_usage = """ `{prefix}ftc 5667` - show information on team 5667, Robominers @@ -287,7 +287,7 @@ async def team(self, ctx: DozerContext, team_num: int): @ftc.command(aliases=["teamsearch", "ftcsearch", "search"]) @bot_has_permissions(embed_links=True) @app_commands.describe(team_name="The name of the team you're interested in searching for") - async def searchteam(self, ctx: DozerContext,*, team_name: str): + async def searchteam(self, ctx: DozerContext, team_name: str): """Search for an FTC team by name.""" if team_name.isdigit(): await self.team.callback(self, ctx, int(team_name)) From a668d73dce7e1c76dfb502091e419ec9fd0f73c4 Mon Sep 17 00:00:00 2001 From: Stephan K <55259393+skruglov2023@users.noreply.github.com> Date: Fri, 11 Apr 2025 15:31:02 -0500 Subject: [PATCH 5/5] Quick update Had a random thought - it might help if someone's looking for a team to specify their location as well in the initial search, in case there's 2 or more teams with similar names in the same area. --- dozer/cogs/ftc.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dozer/cogs/ftc.py b/dozer/cogs/ftc.py index e9eace20..8004a762 100755 --- a/dozer/cogs/ftc.py +++ b/dozer/cogs/ftc.py @@ -314,8 +314,9 @@ async def searchteam(self, ctx: DozerContext, team_name: str): e = discord.Embed(color=embed_color, title=f"FTC Team Search: {team_name}") for team in team_data: - e.add_field(name = f"Team {team['number']}", value = team['name'], inline = False) - + e.add_field(name = f"Team {team['number']} - **{team['name']}**", + value = f"{team['city']}, {(team['state'] + ', ') if not team['state'].isdigit() else ''}{team['country']}", + inline = False) e.set_footer(text = "Team information from FTCScout") view = discord.ui.View()