From c8392342a66b6328b7dfee0b42ce1b10c85922ec Mon Sep 17 00:00:00 2001 From: stijndcl Date: Thu, 14 Jul 2022 20:28:45 +0200 Subject: [PATCH] Urban dictionary commands --- .github/workflows/python.yml | 2 + codecov.yaml | 2 +- didier/cogs/other.py | 5 +- didier/data/apis/urban_dictionary.py | 5 +- didier/data/embeds/base.py | 2 +- didier/data/embeds/urban_dictionary.py | 40 ++++- didier/utils/discord/constants.py | 17 ++ didier/utils/discord/menus/__init__.py | 0 didier/utils/types/string.py | 14 +- pyproject.toml | 3 +- readme.md | 2 + .../test_data/urban_dictionary_response.json | 150 +++++++++++++----- 12 files changed, 198 insertions(+), 44 deletions(-) create mode 100644 didier/utils/discord/constants.py create mode 100644 didier/utils/discord/menus/__init__.py diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index b083e02..75e7e92 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -59,6 +59,8 @@ jobs: coverage xml - name: Upload coverage report to CodeCov uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV }} linting: needs: [dependencies] runs-on: ubuntu-latest diff --git a/codecov.yaml b/codecov.yaml index 6ce17c3..e916d57 100644 --- a/codecov.yaml +++ b/codecov.yaml @@ -10,5 +10,5 @@ coverage: precision: 5 ignore: - - "./tests/*" - "./didier/cogs/*" # Cogs can't really be tested properly + - "./tests/*" diff --git a/didier/cogs/other.py b/didier/cogs/other.py index 93098ac..6a036e2 100644 --- a/didier/cogs/other.py +++ b/didier/cogs/other.py @@ -12,10 +12,11 @@ class Other(commands.Cog): def __init__(self, client: Didier): self.client = client - @commands.command(name="Define", aliases=["Ud", "Urban"], usage="[Woord]") + @commands.hybrid_command(name="define", description="Urban Dictionary", aliases=["Ud", "Urban"], usage="[Woord]") async def define(self, ctx: commands.Context, *, query: str): """Look up the definition of a word on the Urban Dictionary""" - definitions = urban_dictionary.lookup(self.client.http_session, query) + definitions = await urban_dictionary.lookup(self.client.http_session, query) + await ctx.reply(embed=definitions[0].to_embed(), mention_author=False) async def setup(client: Didier): diff --git a/didier/data/apis/urban_dictionary.py b/didier/data/apis/urban_dictionary.py index ac42b9c..40381ea 100644 --- a/didier/data/apis/urban_dictionary.py +++ b/didier/data/apis/urban_dictionary.py @@ -2,7 +2,10 @@ from aiohttp import ClientSession from didier.data.embeds.urban_dictionary import Definition -__all__ = ["lookup"] +__all__ = ["lookup", "PER_PAGE"] + + +PER_PAGE = 10 async def lookup(http_session: ClientSession, query: str) -> list[Definition]: diff --git a/didier/data/embeds/base.py b/didier/data/embeds/base.py index 38d7c61..8cab519 100644 --- a/didier/data/embeds/base.py +++ b/didier/data/embeds/base.py @@ -18,5 +18,5 @@ class EmbedBaseModel(ABC): raise NotImplementedError -class EmbedPydantic(ABC, EmbedBaseModel, BaseModel): +class EmbedPydantic(EmbedBaseModel, BaseModel, ABC): """Pydantic version of EmbedModel""" diff --git a/didier/data/embeds/urban_dictionary.py b/didier/data/embeds/urban_dictionary.py index 99a9a92..14086bb 100644 --- a/didier/data/embeds/urban_dictionary.py +++ b/didier/data/embeds/urban_dictionary.py @@ -2,8 +2,12 @@ from datetime import datetime import discord from overrides import overrides +from pydantic import validator from didier.data.embeds.base import EmbedPydantic +from didier.utils.discord import colours +from didier.utils.discord.constants import Limits +from didier.utils.types import string as string_utils __all__ = ["Definition"] @@ -13,12 +17,46 @@ class Definition(EmbedPydantic): word: str definition: str + example: str permalink: str author: str thumbs_up: int thumbs_down: int written_on: datetime + @property + def ratio(self) -> float: + """The up vote/down vote ratio + + This ratio is rounded down to 2 decimal places + If the amount of down votes is 0, always return 100% + """ + # No down votes, possibly no up votes either + # Avoid a 0/0 situation + if self.thumbs_down == 0: + return 100 + + total_votes = self.thumbs_up + self.thumbs_down + return round(100 * self.thumbs_up / total_votes, 2) + + @validator("definition", "example") + def modify_long_text(cls, field): + """Remove brackets from fields & cut them off if they are too long""" + field = field.replace("[", "").replace("]", "") + return string_utils.abbreviate(field, max_length=Limits.EMBED_FIELD_VALUE_LENGTH) + @overrides def to_embed(self) -> discord.Embed: - embed = discord.Embed() + embed = discord.Embed(colour=colours.urban_dictionary_green()) + embed.set_author(name="Urban Dictionary") + + embed.add_field(name="Woord", value=self.word, inline=True) + embed.add_field(name="Auteur", value=self.author, inline=True) + embed.add_field(name="Definitie", value=self.definition, inline=False) + embed.add_field(name="Voorbeeld", value=self.example or "\u200B", inline=False) + embed.add_field( + name="Rating", value=f"{self.ratio}% ({self.thumbs_up}/{self.thumbs_up + self.thumbs_down})", inline=True + ) + embed.add_field(name="Link", value=f"[Urban Dictionary]({self.permalink})", inline=True) + + return embed diff --git a/didier/utils/discord/constants.py b/didier/utils/discord/constants.py new file mode 100644 index 0000000..707d635 --- /dev/null +++ b/didier/utils/discord/constants.py @@ -0,0 +1,17 @@ +from enum import Enum + +__all__ = ["Limits"] + + +class Limits(int, Enum): + """Enum for the limits of certain fields""" + + EMBED_AUTHOR_LENGTH = 256 + EMBED_DESCRIPTION_LENGTH = 4096 + EMBED_FIELD_COUNT = 25 + EMBED_FIELD_NAME_LENGTH = 256 + EMBED_FIELD_VALUE_LENGTH = 1024 + EMBED_FOOTER_LENGTH = 2048 + EMBED_TITLE_LENGTH = 256 + EMBED_TOTAL_LENGTH = 6000 + MESSAGE_LENGTH = 2000 diff --git a/didier/utils/discord/menus/__init__.py b/didier/utils/discord/menus/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/didier/utils/types/string.py b/didier/utils/types/string.py index 3f383a6..015996a 100644 --- a/didier/utils/types/string.py +++ b/didier/utils/types/string.py @@ -1,7 +1,19 @@ import math from typing import Optional -__all__ = ["leading", "pluralize"] +__all__ = ["abbreviate", "leading", "pluralize"] + + +def abbreviate(text: str, max_length: int) -> str: + """Abbreviate a string to a maximum length + + If the string is longer, add an ellipsis (...) at the end + """ + if len(text) <= max_length: + return text + + # Strip to avoid ending on random double newlines + return text[: max_length - 1].strip() + "…" def leading(character: str, string: str, target_length: Optional[int] = 2) -> str: diff --git a/pyproject.toml b/pyproject.toml index a5ac198..2a28e94 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,8 @@ omit = [ "./database/migrations.py", "./didier/cogs/*", "./didier/didier.py", - "./didier/data/*" + "./didier/data/*", + "./didier/utils/discord/colours.py" ] [tool.isort] diff --git a/readme.md b/readme.md index 2c2e678..58e55e9 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,7 @@ # Didier +[![wakatime](https://wakatime.com/badge/user/3543d4ec-ec93-4b43-abd6-2bc2e310f3c4/project/100156e4-2fb5-40b4-b808-e47ef687905c.svg)](https://wakatime.com/badge/user/3543d4ec-ec93-4b43-abd6-2bc2e310f3c4/project/100156e4-2fb5-40b4-b808-e47ef687905c) + You bet. The time has come. ### Discord Documentation diff --git a/tests/test_data/urban_dictionary_response.json b/tests/test_data/urban_dictionary_response.json index 04cedd5..071a880 100644 --- a/tests/test_data/urban_dictionary_response.json +++ b/tests/test_data/urban_dictionary_response.json @@ -1,56 +1,134 @@ { "list": [ { - "definition": "When you fall [asleep] [tweeting] about [nonsensical] things", - "permalink": "http://cofveve.urbanup.com/11642742", - "thumbs_up": 170, + "definition": "It literally means covfefe.\n\nOriginated from [Donald Trump's] [tweet]: \"Despite the constant [negative press] covfefe\"", + "permalink": "http://covfefe.urbanup.com/11630874", + "thumbs_up": 14701, "sound_urls": [], - "author": "Bonafidé", - "word": "cofveve", - "defid": 11642742, + "author": "lightinglax", + "word": "covfefe", + "defid": 11630874, "current_vote": "", - "written_on": "2017-06-03T00:32:10.987Z", - "example": "[Despite] [the negative] [press] cofveve", - "thumbs_down": 30 + "written_on": "2017-05-31T04:54:39.112Z", + "example": "\"[It's time] to [nuke this] place down.\" \"What's [the code]?\" \"covfefe.\"", + "thumbs_down": 2337 }, { - "definition": "when you want to type [conference] and your hands are too small to reach [the keys] (someone else's [brill] def)", - "permalink": "http://cofveve.urbanup.com/11662158", - "thumbs_up": 69, + "definition": "An [unpresidented] [typo]", + "permalink": "http://covfefe.urbanup.com/11631018", + "thumbs_up": 2295, "sound_urls": [], - "author": "blacklist2017", - "word": "cofveve", - "defid": 11662158, + "author": "John Wilkes Bluetooth", + "word": "covfefe", + "defid": 11631018, "current_vote": "", - "written_on": "2017-06-07T00:44:36.793Z", - "example": "\"[i want] to [shut down] this [press] cofveve...", - "thumbs_down": 16 + "written_on": "2017-05-31T05:21:10.475Z", + "example": "[Despite] the [constant] [negative press] covfefe", + "thumbs_down": 776 }, { - "definition": "[Bullshit]", - "permalink": "http://cofveve.urbanup.com/12386593", - "thumbs_up": 5, + "definition": "Originally coined by Donald Trump, [45th President of the United States] of America, covfefe will inevitably come to be syonymous with sending a text or [publishing] a tweet prematurely and with [egregious] spelling errors.", + "permalink": "http://covfefe.urbanup.com/11631031", + "thumbs_up": 3182, "sound_urls": [], - "author": "FreedomTodd", - "word": "Cofveve", - "defid": 12386593, + "author": "covfefe89", + "word": "covfefe", + "defid": 11631031, "current_vote": "", - "written_on": "2018-01-06T17:52:59.822Z", - "example": "[I’m] [full of] [cofveve]", - "thumbs_down": 6 + "written_on": "2017-05-31T05:23:13.478Z", + "example": "Damn dog, I just covfefed tryna ask Ashley out. I meant to text her to get a drink but instead i wrote \"despite the constant [negative press] [convfefe].\" She's gonna think I'm [mad stupid] now.", + "thumbs_down": 1325 }, { - "definition": "When you dip [an apple] in a chocolate [Starbucks] [frappe]", - "permalink": "http://razzle-cofveve.urbanup.com/12006856", - "thumbs_up": 0, + "definition": "¯\\_(ツ)_/¯", + "permalink": "http://covfefe.urbanup.com/11630896", + "thumbs_up": 245, "sound_urls": [], - "author": "harry potter theme song si ", - "word": "razzle cofveve", - "defid": 12006856, + "author": "zanzalaz", + "word": "covfefe", + "defid": 11630896, "current_vote": "", - "written_on": "2017-09-30T03:00:54.233Z", - "example": "[My friend] loves [apples] and [Starbucks], so the razzle cofveve was perfect!", - "thumbs_down": 0 + "written_on": "2017-05-31T04:56:45.441Z", + "example": "\"[Despite] the [constant] [negative press] covfefe\"", + "thumbs_down": 105 + }, + { + "definition": "The [nuclear codes].", + "permalink": "http://covfefe.urbanup.com/11630856", + "thumbs_up": 830, + "sound_urls": [], + "author": "gosty7", + "word": "covfefe", + "defid": 11630856, + "current_vote": "", + "written_on": "2017-05-31T04:52:01.695Z", + "example": "[Despite] the [constant] [negative press] covfefe", + "thumbs_down": 445 + }, + { + "definition": "No one really knows yet, but the President of the United States of America used it in a tweet so it must be a [bigly] important word. It must be [YUGE] somewhere as he knows [all the best words].", + "permalink": "http://covfefe.urbanup.com/11630902", + "thumbs_up": 2711, + "sound_urls": [], + "author": "CovfefeFan", + "word": "covfefe", + "defid": 11630902, + "current_vote": "", + "written_on": "2017-05-31T04:57:30.841Z", + "example": "[Despite] the [constant] [negative press] covfefe", + "thumbs_down": 1612 + }, + { + "definition": "an [alternative fact] for [the word] 'coverage'", + "permalink": "http://covfefe.urbanup.com/11631148", + "thumbs_up": 92, + "sound_urls": [], + "author": "ceckhardt", + "word": "covfefe", + "defid": 11631148, + "current_vote": "", + "written_on": "2017-05-31T05:51:21.446Z", + "example": "\"[Despite] [constant] [negative press] covfefe\"", + "thumbs_down": 52 + }, + { + "definition": "Acronym : descriptive [--] Can’t [Operate] Very Fucking Efficiently [Faking] Effectiveness", + "permalink": "http://covfefe.urbanup.com/11634131", + "thumbs_up": 40, + "sound_urls": [], + "author": "Robert the Punster", + "word": "covfefe", + "defid": 11634131, + "current_vote": "", + "written_on": "2017-05-31T21:36:36.704Z", + "example": "[Some people] covfefe", + "thumbs_down": 22 + }, + { + "definition": "A word [Trump] [tweeted] and [nobody knows] what the hell it means.", + "permalink": "http://covfefe.urbanup.com/11630891", + "thumbs_up": 105, + "sound_urls": [], + "author": "pmince", + "word": "covfefe", + "defid": 11630891, + "current_vote": "", + "written_on": "2017-05-31T04:56:21.018Z", + "example": "[Despite] the [constant] [negative press] covfefe", + "thumbs_down": 75 + }, + { + "definition": "(N) Word used to describe a person with so much [egotism] that he/she cannot [admit] he/she made even the simplest of [mistakes].", + "permalink": "http://covfefe.urbanup.com/11636070", + "thumbs_up": 28, + "sound_urls": [], + "author": "PJ the Coug", + "word": "covfefe", + "defid": 11636070, + "current_vote": "", + "written_on": "2017-06-01T06:33:01.986Z", + "example": "\"[Kevin] [fell asleep] playing online last night. He just said he was 'afk' for [four] hours. He's got a lot of covfefe.\"", + "thumbs_down": 17 } ] } \ No newline at end of file