import logging from html import unescape from urllib.parse import quote_plus from discord import Embed, HTTPException from discord.ext import commands from bot.bot import Bot from bot.constants import Colours, Emojis logger = logging.getLogger(__name__) BASE_URL = "https://api.stackexchange.com/2.2/search/advanced" SO_PARAMS = { "order": "desc", "sort": "activity", "site": "stackoverflow" } SEARCH_URL = "https://stackoverflow.com/search?q={query}" ERR_EMBED = Embed( title="Error in fetching results from Stackoverflow", description=( "Sorry, there was en error while trying to fetch data from the Stackoverflow website. Please try again in some " "time. If this issue persists, please contact the staff or send a message in #dev-contrib." ), color=Colours.soft_red ) class Stackoverflow(commands.Cog): """Contains command to interact with stackoverflow from discord.""" def __init__(self, bot: Bot): self.bot = bot @commands.command(aliases=["so"]) @commands.cooldown(1, 15, commands.cooldowns.BucketType.user) async def stackoverflow(self, ctx: commands.Context, *, search_query: str) -> None: """Sends the top 5 results of a search query from stackoverflow.""" params = SO_PARAMS | {"q": search_query} async with self.bot.http_session.get(url=BASE_URL, params=params) as response: if response.status == 200: data = await response.json() else: logger.error(f'Status code is not 200, it is {response.status}') await ctx.send(embed=ERR_EMBED) return if not data['items']: no_search_result = Embed( title=f"No search results found for {search_query}", color=Colours.soft_red ) await ctx.send(embed=no_search_result) return top5 = data["items"][:5] encoded_search_query = quote_plus(search_query) embed = Embed( title="Search results - Stackoverflow", url=SEARCH_URL.format(query=encoded_search_query), description=f"Here are the top {len(top5)} results:", color=Colours.orange ) for item in top5: embed.add_field( name=unescape(item['title']), value=( f"[{Emojis.reddit_upvote} {item['score']} " f"{Emojis.stackoverflow_views} {item['view_count']} " f"{Emojis.reddit_comments} {item['answer_count']} " f"{Emojis.stackoverflow_tag} {', '.join(item['tags'][:3])}]" f"({item['link']})" ), inline=False) embed.set_footer(text="View the original link for more results.") try: await ctx.send(embed=embed) except HTTPException: search_query_too_long = Embed( title="Your search query is too long, please try shortening your search query", color=Colours.soft_red ) await ctx.send(embed=search_query_too_long) async def setup(bot: Bot) -> None: """Load the Stackoverflow Cog.""" await bot.add_cog(Stackoverflow(bot))