mirror of https://github.com/stijndcl/didier
Merge pull request #90 from stijndcl/slash_commands
First slash commands & small fixes/cleanupspull/91/head
commit
5e946ed5d3
|
@ -19,7 +19,7 @@ ipc_client = ipc.Client(secret_key="SOME_SECRET_KEY")
|
||||||
@app.route("/ping", methods=["GET"])
|
@app.route("/ping", methods=["GET"])
|
||||||
async def ping():
|
async def ping():
|
||||||
"""
|
"""
|
||||||
Send a ping request, monitors bot latency, endpoint time, and PSQL latency
|
Send a ping request, monitors bot latency and endpoint time
|
||||||
"""
|
"""
|
||||||
latency = await ipc_client.request("get_bot_latency")
|
latency = await ipc_client.request("get_bot_latency")
|
||||||
|
|
||||||
|
|
|
@ -163,8 +163,8 @@ class Birthdays(commands.Cog):
|
||||||
|
|
||||||
# Create a datetime object for this birthday
|
# Create a datetime object for this birthday
|
||||||
timeString = "{}/{}/{}".format(
|
timeString = "{}/{}/{}".format(
|
||||||
stringFormatters.leadingZero(str(day)),
|
stringFormatters.leading_zero(str(day)),
|
||||||
stringFormatters.leadingZero(str(month)),
|
stringFormatters.leading_zero(str(month)),
|
||||||
year
|
year
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
import os
|
from data.embeds.urban_dictionary import Definition
|
||||||
|
|
||||||
from decorators import help
|
from decorators import help
|
||||||
import discord
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from enums.help_categories import Category
|
from enums.help_categories import Category
|
||||||
from functions import checks
|
from functions import checks
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
class Define(commands.Cog):
|
class Define(commands.Cog):
|
||||||
|
@ -19,99 +16,15 @@ class Define(commands.Cog):
|
||||||
@commands.command(name="Define", aliases=["UrbanDictionary", "Ud"], usage="[Woord]")
|
@commands.command(name="Define", aliases=["UrbanDictionary", "Ud"], usage="[Woord]")
|
||||||
@commands.check(checks.allowedChannels)
|
@commands.check(checks.allowedChannels)
|
||||||
@help.Category(category=Category.Other)
|
@help.Category(category=Category.Other)
|
||||||
async def define(self, ctx, *words):
|
async def define(self, ctx, *, query):
|
||||||
"""
|
"""
|
||||||
Command that looks up the definition of a word in the Urban Dictionary.
|
Command that looks up the definition of a word in the Urban Dictionary.
|
||||||
:param ctx: Discord Context
|
:param ctx: Discord Context
|
||||||
:param words: Word(s) to look up
|
:param query: Word(s) to look up
|
||||||
"""
|
"""
|
||||||
words = list(words)
|
embed = Definition(query).to_embed()
|
||||||
if len(words) == 0:
|
|
||||||
return await ctx.send("Controleer je argumenten.")
|
|
||||||
|
|
||||||
query = " ".join(words)
|
|
||||||
answer = self.lookup(query)
|
|
||||||
|
|
||||||
embed = discord.Embed(colour=discord.Colour.from_rgb(220, 255, 0))
|
|
||||||
embed.set_author(name="Urban Dictionary")
|
|
||||||
|
|
||||||
embed.add_field(name="Woord", value=answer["word"], inline=True)
|
|
||||||
embed.add_field(name="Auteur", value=answer["author"], inline=True)
|
|
||||||
embed.add_field(name="Definitie", value=self.cleanString(answer["definition"]), inline=False)
|
|
||||||
embed.add_field(name="Voorbeeld", value=self.cleanString(answer["example"]), inline=False)
|
|
||||||
embed.add_field(name="Rating", value=str(round(self.ratio(answer), 2)) + "%")
|
|
||||||
embed.add_field(name="Link naar de volledige definitie",
|
|
||||||
value="[Urban Dictionary]({})".format(str(answer["link"])))
|
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
def lookup(self, word):
|
|
||||||
"""
|
|
||||||
Function that sends the API request to get the definition.
|
|
||||||
:param word: the woord to look up
|
|
||||||
:return: a dictionary representing the info of this word
|
|
||||||
"""
|
|
||||||
url = "https://mashape-community-urban-dictionary.p.rapidapi.com/define"
|
|
||||||
|
|
||||||
querystring = {"term": word}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
'x-rapidapi-host': "mashape-community-urban-dictionary.p.rapidapi.com",
|
|
||||||
'x-rapidapi-key': os.getenv("URBANDICTIONARY")
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
if word.lower() == "didier":
|
|
||||||
raise Exception
|
|
||||||
|
|
||||||
response = requests.request("GET", url, headers=headers, params=querystring).json()["list"]
|
|
||||||
|
|
||||||
if len(response) > 0:
|
|
||||||
return {"word": response[0]["word"], "definition": response[0]["definition"],
|
|
||||||
"example": response[0]["example"], "thumbs_up": response[0]["thumbs_up"],
|
|
||||||
"thumbs_down": response[0]["thumbs_down"], "link": response[0]["permalink"],
|
|
||||||
"author": response[0]["author"]}
|
|
||||||
|
|
||||||
# No valid response
|
|
||||||
return self.defineDidier()
|
|
||||||
except Exception:
|
|
||||||
return self.defineDidier()
|
|
||||||
|
|
||||||
def cleanString(self, text: str):
|
|
||||||
"""
|
|
||||||
Function that cuts off definitions that are too long & strips out UD markdown
|
|
||||||
from an input string.
|
|
||||||
:param text: the input string to clean up
|
|
||||||
:return: the edited version of the string
|
|
||||||
"""
|
|
||||||
text = text.replace("[", "")
|
|
||||||
text = text.replace("]", "")
|
|
||||||
|
|
||||||
if not text:
|
|
||||||
return "N/A"
|
|
||||||
|
|
||||||
return text if len(text) < 1024 else text[:1021] + "..."
|
|
||||||
|
|
||||||
def ratio(self, dic):
|
|
||||||
"""
|
|
||||||
Function that alculates the upvote/downvote ratio of the definition.
|
|
||||||
:param dic: the dictionary representing the definition
|
|
||||||
:return: the upvote/downvote ratio (float)
|
|
||||||
"""
|
|
||||||
return (100 * int(dic["thumbs_up"])) / (int(dic["thumbs_up"]) + int(dic["thumbs_down"])) \
|
|
||||||
if int(dic["thumbs_down"]) != 0 else 100.0
|
|
||||||
|
|
||||||
def defineDidier(self):
|
|
||||||
"""
|
|
||||||
Function that returns a stock dictionary to define Didier
|
|
||||||
in case people call it, or no definition was found.
|
|
||||||
:return: a dictionary that defines Didier
|
|
||||||
"""
|
|
||||||
return {"word": "Didier", "definition": "Didier", "example": "1: Didier\n2: Hmm?", "thumbs_up": 69420,
|
|
||||||
"thumbs_down": 0, "author": "Didier",
|
|
||||||
"link": "https://upload.wikimedia.org/wikipedia/commons/a/a5"
|
|
||||||
"/Didier_Reynders_in_Iranian_Parliament_02.jpg"}
|
|
||||||
|
|
||||||
|
|
||||||
def setup(client):
|
def setup(client):
|
||||||
client.add_cog(Define(client))
|
client.add_cog(Define(client))
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
|
from dislash import SlashInteraction
|
||||||
|
|
||||||
from data import constants
|
from data import constants
|
||||||
from data.snipe import Snipe, Action, should_snipe
|
from data.snipe import Snipe, Action, should_snipe
|
||||||
import datetime
|
import datetime
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from functions import checks, easterEggResponses
|
from functions import checks, easterEggResponses, stringFormatters
|
||||||
from functions.database import stats, muttn, custom_commands, commands as command_stats
|
from functions.database import stats, muttn, custom_commands, commands as command_stats
|
||||||
import pytz
|
import pytz
|
||||||
from settings import READY_MESSAGE, SANDBOX, STATUS_MESSAGE
|
from settings import READY_MESSAGE, SANDBOX
|
||||||
from startup.didier import Didier
|
from startup.didier import Didier
|
||||||
import time
|
import time
|
||||||
import traceback
|
|
||||||
|
|
||||||
|
|
||||||
class Events(commands.Cog):
|
class Events(commands.Cog):
|
||||||
|
@ -33,9 +34,6 @@ class Events(commands.Cog):
|
||||||
"""
|
"""
|
||||||
Function called when the bot is ready & done leading.
|
Function called when the bot is ready & done leading.
|
||||||
"""
|
"""
|
||||||
# Set status
|
|
||||||
await self.client.change_presence(status=discord.Status.online, activity=discord.Game(STATUS_MESSAGE))
|
|
||||||
|
|
||||||
print(READY_MESSAGE)
|
print(READY_MESSAGE)
|
||||||
|
|
||||||
# Add constants to the client as a botvar
|
# Add constants to the client as a botvar
|
||||||
|
@ -87,12 +85,9 @@ class Events(commands.Cog):
|
||||||
Logs commands in your terminal.
|
Logs commands in your terminal.
|
||||||
:param ctx: Discord Context
|
:param ctx: Discord Context
|
||||||
"""
|
"""
|
||||||
DM = ctx.guild is None
|
print(stringFormatters.format_command_usage(ctx))
|
||||||
print("{} in {}: {}".format(ctx.author.display_name,
|
|
||||||
"DM" if DM else "{} ({})".format(ctx.channel.name, ctx.guild.name),
|
|
||||||
ctx.message.content))
|
|
||||||
|
|
||||||
command_stats.invoked()
|
command_stats.invoked(command_stats.InvocationType.TextCommand)
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_command_error(self, ctx, err):
|
async def on_command_error(self, ctx, err):
|
||||||
|
@ -101,8 +96,8 @@ class Events(commands.Cog):
|
||||||
:param ctx: Discord Context
|
:param ctx: Discord Context
|
||||||
:param err: the error thrown
|
:param err: the error thrown
|
||||||
"""
|
"""
|
||||||
# Zandbak Didier shouldn't spam the error logs
|
# Debugging Didier shouldn't spam the error logs
|
||||||
if self.client.user.id == int(constants.coolerDidierId):
|
if self.client.user.id != int(constants.didierId):
|
||||||
raise err
|
raise err
|
||||||
|
|
||||||
# Don't handle commands that have their own custom error handler
|
# Don't handle commands that have their own custom error handler
|
||||||
|
@ -123,14 +118,26 @@ class Events(commands.Cog):
|
||||||
elif isinstance(err, (commands.BadArgument, commands.MissingRequiredArgument, commands.UnexpectedQuoteError)):
|
elif isinstance(err, (commands.BadArgument, commands.MissingRequiredArgument, commands.UnexpectedQuoteError)):
|
||||||
await ctx.send("Controleer je argumenten.")
|
await ctx.send("Controleer je argumenten.")
|
||||||
else:
|
else:
|
||||||
# Remove the InvokeCommandError because it's useless information
|
usage = stringFormatters.format_command_usage(ctx)
|
||||||
x = traceback.format_exception(type(err), err, err.__traceback__)
|
await self.sendErrorEmbed(err, "Command", usage)
|
||||||
errorString = ""
|
|
||||||
for line in x:
|
@commands.Cog.listener()
|
||||||
if "direct cause of the following" in line:
|
async def on_slash_command(self, interaction: SlashInteraction):
|
||||||
break
|
"""
|
||||||
errorString += line.replace("*", "") + "\n" if line.strip() != "" else ""
|
Function called whenever someone uses a slash command
|
||||||
await self.sendErrorEmbed(ctx, err, errorString)
|
"""
|
||||||
|
print(stringFormatters.format_slash_command_usage(interaction))
|
||||||
|
|
||||||
|
command_stats.invoked(command_stats.InvocationType.SlashCommand)
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_slash_command_error(self, interaction, err):
|
||||||
|
# Debugging Didier shouldn't spam the error logs
|
||||||
|
if self.client.user.id != int(constants.didierId):
|
||||||
|
raise err
|
||||||
|
|
||||||
|
usage = stringFormatters.format_slash_command_usage(interaction)
|
||||||
|
await self.sendErrorEmbed(err, "Slash Command", usage)
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_raw_reaction_add(self, react):
|
async def on_raw_reaction_add(self, react):
|
||||||
|
@ -286,19 +293,15 @@ class Events(commands.Cog):
|
||||||
self.client.snipe[message.channel.id] = Snipe(message.author.id, message.channel.id, message.guild.id,
|
self.client.snipe[message.channel.id] = Snipe(message.author.id, message.channel.id, message.guild.id,
|
||||||
Action.Remove, message.content)
|
Action.Remove, message.content)
|
||||||
|
|
||||||
async def sendErrorEmbed(self, ctx, error: Exception, trace):
|
async def sendErrorEmbed(self, error: Exception, error_type: str, usage: str):
|
||||||
"""
|
"""
|
||||||
Function that sends an error embed in #ErrorLogs.
|
Function that sends an error embed in #ErrorLogs.
|
||||||
:param ctx: Discord Context
|
|
||||||
:param error: the error thrown
|
|
||||||
:param trace: the stacktrace of the error
|
|
||||||
"""
|
"""
|
||||||
|
trace = stringFormatters.format_error_tb(error)
|
||||||
|
|
||||||
embed = discord.Embed(colour=discord.Colour.red())
|
embed = discord.Embed(colour=discord.Colour.red())
|
||||||
embed.set_author(name="Error")
|
embed.set_author(name="Error")
|
||||||
embed.add_field(name="Command:", value="{} in {}: {}".format(ctx.author.display_name,
|
embed.add_field(name=f"{error_type}:", value=usage, inline=False)
|
||||||
ctx.channel.name if str(
|
|
||||||
ctx.channel.type) != "private" else "DM",
|
|
||||||
ctx.message.content), inline=False)
|
|
||||||
embed.add_field(name="Error:", value=str(error)[:1024], inline=False)
|
embed.add_field(name="Error:", value=str(error)[:1024], inline=False)
|
||||||
embed.add_field(name="Message:", value=str(trace)[:1024], inline=False)
|
embed.add_field(name="Message:", value=str(trace)[:1024], inline=False)
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ class Faq(commands.Cog):
|
||||||
return await self.faqCategory(ctx, (constants.faq_channels[ctx.channel.id],))
|
return await self.faqCategory(ctx, (constants.faq_channels[ctx.channel.id],))
|
||||||
|
|
||||||
# List of all categories with the first letter capitalized
|
# List of all categories with the first letter capitalized
|
||||||
resp = [stringFormatters.titleCase(cat[0]) for cat in faq.getCategories()]
|
resp = [stringFormatters.title_case(cat[0]) for cat in faq.getCategories()]
|
||||||
|
|
||||||
# Sort alphabetically
|
# Sort alphabetically
|
||||||
resp.sort()
|
resp.sort()
|
||||||
|
@ -146,7 +146,7 @@ class Faq(commands.Cog):
|
||||||
resp.sort(key=lambda x: int(x[0]))
|
resp.sort(key=lambda x: int(x[0]))
|
||||||
|
|
||||||
embed = discord.Embed(colour=discord.Colour.blue())
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
embed.set_author(name="FAQ {}".format(stringFormatters.titleCase(category)))
|
embed.set_author(name="FAQ {}".format(stringFormatters.title_case(category)))
|
||||||
|
|
||||||
# Add everything into the embed
|
# Add everything into the embed
|
||||||
for i, pair in enumerate(resp):
|
for i, pair in enumerate(resp):
|
||||||
|
|
|
@ -2,7 +2,7 @@ from decorators import help
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from enums.help_categories import Category
|
from enums.help_categories import Category
|
||||||
from functions import checks, config
|
from functions import checks, config
|
||||||
from functions.football import getMatches, getTable, get_jpl_code
|
from functions.football import get_matches, get_table, get_jpl_code
|
||||||
|
|
||||||
|
|
||||||
class Football(commands.Cog):
|
class Football(commands.Cog):
|
||||||
|
@ -20,21 +20,16 @@ class Football(commands.Cog):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@jpl.command(name="Matches", aliases=["M"], usage="[Week]*")
|
@jpl.command(name="Matches", aliases=["M"], usage="[Week]*")
|
||||||
async def matches(self, ctx, *args):
|
async def matches(self, ctx, day: int = None):
|
||||||
args = list(args)
|
|
||||||
|
|
||||||
# Default is current day
|
# Default is current day
|
||||||
if not args:
|
if day is None:
|
||||||
args = [str(config.get("jpl_day"))]
|
day = int(config.get("jpl_day"))
|
||||||
|
|
||||||
if all(letter.isdigit() for letter in args[0]):
|
await ctx.send(get_matches(day))
|
||||||
await ctx.send(getMatches(int(args[0])))
|
|
||||||
else:
|
|
||||||
return await ctx.send("Dit is geen geldige speeldag.")
|
|
||||||
|
|
||||||
@jpl.command(name="Table", aliases=["Ranking", "Rankings", "Ranks", "T"])
|
@jpl.command(name="Table", aliases=["Ranking", "Rankings", "Ranks", "T"])
|
||||||
async def table(self, ctx, *args):
|
async def table(self, ctx):
|
||||||
await ctx.send(getTable())
|
await ctx.send(get_table())
|
||||||
|
|
||||||
@commands.check(checks.isMe)
|
@commands.check(checks.isMe)
|
||||||
@jpl.command(name="Update")
|
@jpl.command(name="Update")
|
||||||
|
|
|
@ -120,7 +120,7 @@ class Fun(commands.Cog):
|
||||||
memeList = memes.getAllMemes()
|
memeList = memes.getAllMemes()
|
||||||
|
|
||||||
# Turn the list into a list of [Name: fields]
|
# Turn the list into a list of [Name: fields]
|
||||||
memeList = [": ".join([stringFormatters.titleCase(meme[1]),
|
memeList = [": ".join([stringFormatters.title_case(meme[1]),
|
||||||
str(meme[2])]) for meme in sorted(memeList, key=lambda x: x[1])]
|
str(meme[2])]) for meme in sorted(memeList, key=lambda x: x[1])]
|
||||||
|
|
||||||
pages = paginatedLeaderboard.Pages(source=paginatedLeaderboard.Source(memeList, "Memes", discord.Colour.blue()),
|
pages = paginatedLeaderboard.Pages(source=paginatedLeaderboard.Source(memeList, "Memes", discord.Colour.blue()),
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import discord
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from decorators import help
|
from decorators import help
|
||||||
from enums.help_categories import Category
|
from enums.help_categories import Category
|
||||||
from functions.scrapers.google import google_search
|
from functions.scrapers.google import google_search, create_google_embed
|
||||||
|
|
||||||
|
|
||||||
class Google(commands.Cog):
|
class Google(commands.Cog):
|
||||||
|
@ -19,33 +18,12 @@ class Google(commands.Cog):
|
||||||
if not query:
|
if not query:
|
||||||
return await ctx.reply("Je hebt geen query opgegeven.", mention_author=True)
|
return await ctx.reply("Je hebt geen query opgegeven.", mention_author=True)
|
||||||
|
|
||||||
results, status = google_search(" ".join(query))
|
result = google_search(" ".join(query))
|
||||||
|
|
||||||
if results is None:
|
if not result.results:
|
||||||
return await ctx.send("Er ging iets fout (Response {})".format(status))
|
return await ctx.send("Er ging iets fout (Response {})".format(result.status_code))
|
||||||
|
|
||||||
# Filter out all Nones
|
|
||||||
elements = list(filter(lambda x: x is not None, results))
|
|
||||||
|
|
||||||
embed = discord.Embed(colour=discord.Colour.blue())
|
|
||||||
embed.set_author(name="Google Search")
|
|
||||||
|
|
||||||
# Empty list of results
|
|
||||||
if len(elements) == 0:
|
|
||||||
embed.description = "Geen resultaten gevonden."
|
|
||||||
return await ctx.reply(embed=embed, mention_author=False)
|
|
||||||
|
|
||||||
# Cut excess results out
|
|
||||||
if len(elements) > 10:
|
|
||||||
elements = elements[:10]
|
|
||||||
|
|
||||||
links = []
|
|
||||||
|
|
||||||
for index, (link, title) in enumerate(elements):
|
|
||||||
links.append("{}: [{}]({})".format(index + 1, title, link))
|
|
||||||
|
|
||||||
embed.description = "\n".join(links)
|
|
||||||
|
|
||||||
|
embed = create_google_embed(result)
|
||||||
await ctx.reply(embed=embed, mention_author=False)
|
await ctx.reply(embed=embed, mention_author=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -182,15 +182,13 @@ class ModCommands(commands.Cog):
|
||||||
embed = discord.Embed(colour=discord.Colour.blue())
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
|
||||||
embed.set_author(name=user.display_name, icon_url=user.avatar_url)
|
embed.set_author(name=user.display_name, icon_url=user.avatar_url)
|
||||||
embed.add_field(name="Discriminator", value="#{}".format(user.discriminator))
|
embed.add_field(name="Discriminator", value=f"#{user.discriminator}")
|
||||||
embed.add_field(name="Discord id", value=user.id)
|
embed.add_field(name="Discord id", value=user.id)
|
||||||
embed.add_field(name="Bot", value="Nee" if not user.bot else "Ja")
|
embed.add_field(name="Bot", value="Nee" if not user.bot else "Ja")
|
||||||
|
|
||||||
created_local = timeFormatters.epochToDate(user.created_at.timestamp())
|
created_local = timeFormatters.epochToDate(user.created_at.timestamp())
|
||||||
|
|
||||||
embed.add_field(name="Account aangemaakt", value="{}\n({} geleden)".format(
|
embed.add_field(name="Account aangemaakt", value=f"<t:{round(created_local['dateDT'].timestamp())}:R>", inline=False)
|
||||||
created_local["date"], timeFormatters.diffYearBasisString(round(created_local["dateDT"].timestamp()))
|
|
||||||
), inline=False)
|
|
||||||
|
|
||||||
# Check if the user is in the current guild
|
# Check if the user is in the current guild
|
||||||
if ctx.guild is not None:
|
if ctx.guild is not None:
|
||||||
|
@ -199,9 +197,8 @@ class ModCommands(commands.Cog):
|
||||||
if member_instance is not None:
|
if member_instance is not None:
|
||||||
joined_local = timeFormatters.epochToDate(member_instance.joined_at.timestamp())
|
joined_local = timeFormatters.epochToDate(member_instance.joined_at.timestamp())
|
||||||
|
|
||||||
embed.add_field(name="Lid geworden van {} op".format(ctx.guild.name), value="{}\n({} Geleden)".format(
|
embed.add_field(name=f"Lid geworden van {ctx.guild.name}",
|
||||||
joined_local["date"], timeFormatters.diffYearBasisString(round(joined_local["dateDT"].timestamp()))
|
value=f"<t:{round(joined_local['dateDT'].timestamp())}:R>")
|
||||||
))
|
|
||||||
|
|
||||||
embed.add_field(name="Mention String", value=member_instance.mention, inline=False)
|
embed.add_field(name="Mention String", value=member_instance.mention, inline=False)
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ class School(commands.Cog):
|
||||||
embed.set_footer(text="Omwille van de coronamaatregelen is er een beperkter aanbod, en kan je enkel nog eten afhalen. Ter plaatse eten is niet meer mogelijk.")
|
embed.set_footer(text="Omwille van de coronamaatregelen is er een beperkter aanbod, en kan je enkel nog eten afhalen. Ter plaatse eten is niet meer mogelijk.")
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
# @commands.command(name="Les", aliases=["Class", "Classes", "Sched", "Schedule"], usage="[Jaargang]* [Dag]*")
|
# @commands.command(name="Les", aliases=["Class", "Classes", "Sched", "Schedule"], usage="[Dag]*")
|
||||||
# @commands.check(checks.allowedChannels)
|
# @commands.check(checks.allowedChannels)
|
||||||
# @help.Category(category=Category.School)
|
# @help.Category(category=Category.School)
|
||||||
async def les(self, ctx, day=None):
|
async def les(self, ctx, day=None):
|
||||||
|
@ -62,7 +62,7 @@ class School(commands.Cog):
|
||||||
return await ctx.send(embed=s.create_schedule().to_embed())
|
return await ctx.send(embed=s.create_schedule().to_embed())
|
||||||
|
|
||||||
@commands.command(name="Pin", usage="[Message]")
|
@commands.command(name="Pin", usage="[Message]")
|
||||||
@help.Category(category=Category.School)
|
@help.Category(category=Category.Other)
|
||||||
async def pin(self, ctx, message: discord.Message):
|
async def pin(self, ctx, message: discord.Message):
|
||||||
# In case people abuse, check if they're blacklisted
|
# In case people abuse, check if they're blacklisted
|
||||||
blacklist = []
|
blacklist = []
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
from discord.ext import commands
|
||||||
|
from dislash import SlashInteraction, slash_command, Option, OptionType
|
||||||
|
|
||||||
|
from data.embeds.urban_dictionary import Definition
|
||||||
|
from startup.didier import Didier
|
||||||
|
|
||||||
|
|
||||||
|
class DefineSlash(commands.Cog):
|
||||||
|
def __init__(self, client: Didier):
|
||||||
|
self.client: Didier = client
|
||||||
|
|
||||||
|
@slash_command(name="define",
|
||||||
|
description="Urban Dictionary",
|
||||||
|
options=[
|
||||||
|
Option("query", "Search query", OptionType.STRING, required=True)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
async def _define_slash(self, interaction: SlashInteraction, query):
|
||||||
|
embed = Definition(query).to_embed()
|
||||||
|
await interaction.reply(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client: Didier):
|
||||||
|
client.add_cog(DefineSlash(client))
|
|
@ -0,0 +1,44 @@
|
||||||
|
from discord.ext import commands
|
||||||
|
from dislash import SlashInteraction, slash_command, Option, OptionType
|
||||||
|
from functions import config, checks
|
||||||
|
from functions.football import get_matches, get_table, get_jpl_code
|
||||||
|
from startup.didier import Didier
|
||||||
|
|
||||||
|
|
||||||
|
class FootballSlash(commands.Cog):
|
||||||
|
def __init__(self, client: Didier):
|
||||||
|
self.client: Didier = client
|
||||||
|
|
||||||
|
@slash_command(name="jpl", description="Jupiler Pro League commands")
|
||||||
|
async def _jpl_group(self, interaction: SlashInteraction):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@_jpl_group.sub_command(name="matches",
|
||||||
|
description="Schema voor een bepaalde speeldag",
|
||||||
|
options=[
|
||||||
|
Option("day", "Speeldag (default huidige)", OptionType.INTEGER)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
async def _jpl_matches_slash(self, interaction: SlashInteraction, day: int = None):
|
||||||
|
# Default is current day
|
||||||
|
if day is None:
|
||||||
|
day = int(config.get("jpl_day"))
|
||||||
|
|
||||||
|
await interaction.reply(get_matches(day))
|
||||||
|
|
||||||
|
@_jpl_group.sub_command(name="table", description="Huidige rangschikking")
|
||||||
|
async def _jpl_table_slash(self, interaction: SlashInteraction):
|
||||||
|
await interaction.reply(get_table())
|
||||||
|
|
||||||
|
@_jpl_group.sub_command(name="update", description="Update de code voor deze competitie (owner-only)")
|
||||||
|
async def _jpl_update_slash(self, interaction: SlashInteraction):
|
||||||
|
if not await checks.isMe(interaction):
|
||||||
|
return await interaction.reply(f"Je hebt geen toegang tot dit commando.")
|
||||||
|
|
||||||
|
code = get_jpl_code()
|
||||||
|
config.config("jpl", code)
|
||||||
|
await interaction.reply(f"Done (code: {code})")
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client: Didier):
|
||||||
|
client.add_cog(FootballSlash(client))
|
|
@ -0,0 +1,28 @@
|
||||||
|
from discord.ext import commands
|
||||||
|
from dislash import slash_command, SlashInteraction, Option, OptionType
|
||||||
|
from functions.scrapers.google import google_search, create_google_embed
|
||||||
|
from startup.didier import Didier
|
||||||
|
|
||||||
|
|
||||||
|
class GoogleSlash(commands.Cog):
|
||||||
|
def __init__(self, client: Didier):
|
||||||
|
self.client: Didier = client
|
||||||
|
|
||||||
|
@slash_command(name="google",
|
||||||
|
description="Google search",
|
||||||
|
options=[
|
||||||
|
Option("query", "Search query", OptionType.STRING, required=True)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
async def _google_slash(self, interaction: SlashInteraction, query: str):
|
||||||
|
result = google_search(query)
|
||||||
|
|
||||||
|
if not result.results:
|
||||||
|
return await interaction.reply("Er ging iets fout (Response {})".format(result.status_code))
|
||||||
|
|
||||||
|
embed = create_google_embed(result)
|
||||||
|
await interaction.reply(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client: Didier):
|
||||||
|
client.add_cog(GoogleSlash(client))
|
|
@ -0,0 +1,27 @@
|
||||||
|
from discord.ext import commands
|
||||||
|
from dislash import SlashInteraction, slash_command, Option, OptionType
|
||||||
|
|
||||||
|
from data.embeds.translate import Translation
|
||||||
|
from startup.didier import Didier
|
||||||
|
|
||||||
|
|
||||||
|
class TranslateSlash(commands.Cog):
|
||||||
|
def __init__(self, client: Didier):
|
||||||
|
self.client: Didier = client
|
||||||
|
|
||||||
|
@slash_command(
|
||||||
|
name="translate",
|
||||||
|
description="Google Translate",
|
||||||
|
options=[
|
||||||
|
Option("text", "Tekst om te vertalen", OptionType.STRING, required=True),
|
||||||
|
Option("from_lang", "Taal om van te vertalen (default auto-detect)", OptionType.STRING),
|
||||||
|
Option("to_lang", "Taal om naar te vertalen (default NL)", OptionType.STRING)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
async def _translate_slash(self, interaction: SlashInteraction, text: str, from_lang: str = "auto", to_lang: str = "nl"):
|
||||||
|
translation = Translation(text=text, fr=from_lang.lower(), to=to_lang.lower())
|
||||||
|
await interaction.reply(embed=translation.to_embed())
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client: Didier):
|
||||||
|
client.add_cog(TranslateSlash(client))
|
|
@ -35,7 +35,7 @@ class Tasks(commands.Cog):
|
||||||
# Don't do it multiple times a day if bot dc's, ...
|
# Don't do it multiple times a day if bot dc's, ...
|
||||||
with open("files/lastTasks.json", "r") as fp:
|
with open("files/lastTasks.json", "r") as fp:
|
||||||
lastTasks = json.load(fp)
|
lastTasks = json.load(fp)
|
||||||
if int(self.getCurrentHour()) == 0 and int(time.time()) - int(lastTasks["interest"]) > 10000:
|
if int(self.getCurrentHour()) == 4 and int(time.time()) - int(lastTasks["interest"]) > 10000:
|
||||||
users = currency.getAllRows()
|
users = currency.getAllRows()
|
||||||
bitcoinPrice = self.getCurrentBitcoinPrice()
|
bitcoinPrice = self.getCurrentBitcoinPrice()
|
||||||
for user in users:
|
for user in users:
|
||||||
|
@ -188,7 +188,7 @@ class Tasks(commands.Cog):
|
||||||
# Don't do it multiple times a day if bot dc's, ...
|
# Don't do it multiple times a day if bot dc's, ...
|
||||||
with open("files/lastTasks.json", "r") as fp:
|
with open("files/lastTasks.json", "r") as fp:
|
||||||
lastTasks = json.load(fp)
|
lastTasks = json.load(fp)
|
||||||
if int(self.getCurrentHour()) == 7 and int(time.time()) - int(lastTasks["remind"]) > 10000:
|
if int(self.getCurrentHour()) == 4 and int(time.time()) - int(lastTasks["remind"]) > 10000:
|
||||||
reminders = Reminders()
|
reminders = Reminders()
|
||||||
|
|
||||||
weekday = self.getCurrentWeekday()
|
weekday = self.getCurrentWeekday()
|
||||||
|
|
|
@ -2,7 +2,7 @@ from decorators import help
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from enums.help_categories import Category
|
from enums.help_categories import Category
|
||||||
from functions.stringFormatters import titleCase as tc
|
from functions.stringFormatters import title_case as tc
|
||||||
from googletrans import Translator, LANGUAGES
|
from googletrans import Translator, LANGUAGES
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import discord
|
||||||
|
from googletrans import Translator, LANGUAGES
|
||||||
|
from functions.stringFormatters import title_case
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
class Translation:
|
||||||
|
def __init__(self, text: str, fr: str, to: str):
|
||||||
|
self.text = text
|
||||||
|
self.fr = fr
|
||||||
|
self.to = to
|
||||||
|
self.embed: Optional[discord.Embed] = None
|
||||||
|
self.translation = None
|
||||||
|
|
||||||
|
self.translate(text, fr, to)
|
||||||
|
|
||||||
|
def translate(self, query: str, fr: str, to: str):
|
||||||
|
"""
|
||||||
|
Translate [query] into [to]
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
translator = Translator()
|
||||||
|
self.translation = translator.translate(query, to, fr)
|
||||||
|
except ValueError as e:
|
||||||
|
message = str(e)
|
||||||
|
|
||||||
|
if "destination" in message:
|
||||||
|
self._create_error_embed(f"{title_case(to)} is geen geldige taal.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if "source" in message:
|
||||||
|
self._create_error_embed(f"{title_case(fr)} is geen geldige taal.")
|
||||||
|
return
|
||||||
|
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def _create_error_embed(self, message):
|
||||||
|
embed = discord.Embed(colour=discord.Colour.red())
|
||||||
|
embed.set_author(name="Didier Translate")
|
||||||
|
embed.description = message
|
||||||
|
self.embed = embed
|
||||||
|
|
||||||
|
def to_embed(self) -> discord.Embed:
|
||||||
|
# There's an error embed to show
|
||||||
|
if self.embed is not None:
|
||||||
|
return self.embed
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Didier Translate")
|
||||||
|
|
||||||
|
if self.fr == "auto":
|
||||||
|
language = self.translation.src
|
||||||
|
embed.add_field(name="Gedetecteerde taal", value=title_case(LANGUAGES[language]))
|
||||||
|
|
||||||
|
if self.translation.extra_data["confidence"] is not None:
|
||||||
|
embed.add_field(name="Zekerheid", value="{}%".format(self.translation.extra_data["confidence"] * 100))
|
||||||
|
|
||||||
|
embed.add_field(name="Origineel ({})".format(self.translation.src.upper()), value=self.text, inline=False)
|
||||||
|
embed.add_field(name="Vertaling ({})".format(self.to.upper()), value=self.translation.text)
|
||||||
|
|
||||||
|
return embed
|
|
@ -1,6 +1,6 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from discord import Embed, Colour
|
from discord import Embed, Colour
|
||||||
from functions.stringFormatters import leadingZero as lz
|
from functions.stringFormatters import leading_zero as lz
|
||||||
from functions.timeFormatters import intToWeekday
|
from functions.timeFormatters import intToWeekday
|
||||||
from markdownify import markdownify as md
|
from markdownify import markdownify as md
|
||||||
import pytz
|
import pytz
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
import discord
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
|
||||||
|
class Definition:
|
||||||
|
def __init__(self, query: str):
|
||||||
|
self.query = query
|
||||||
|
self.definition = Definition.lookup(query)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def lookup(word) -> Dict:
|
||||||
|
"""
|
||||||
|
Function that sends the API request to get the definition.
|
||||||
|
:param word: the woord to look up
|
||||||
|
:return: a dictionary representing the info of this word
|
||||||
|
"""
|
||||||
|
url = "https://mashape-community-urban-dictionary.p.rapidapi.com/define"
|
||||||
|
|
||||||
|
querystring = {"term": word}
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'x-rapidapi-host': "mashape-community-urban-dictionary.p.rapidapi.com",
|
||||||
|
'x-rapidapi-key': os.getenv("URBANDICTIONARY")
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
if word.lower() == "didier":
|
||||||
|
return Definition.define_didier()
|
||||||
|
|
||||||
|
response = requests.get(url, headers=headers, params=querystring).json()["list"]
|
||||||
|
|
||||||
|
if len(response) > 0:
|
||||||
|
return {"word": response[0]["word"], "definition": response[0]["definition"],
|
||||||
|
"example": response[0]["example"], "thumbs_up": response[0]["thumbs_up"],
|
||||||
|
"thumbs_down": response[0]["thumbs_down"], "link": response[0]["permalink"],
|
||||||
|
"author": response[0]["author"]}
|
||||||
|
|
||||||
|
# No valid response
|
||||||
|
return {}
|
||||||
|
except Exception:
|
||||||
|
return Definition.define_didier()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def clean_string(text: str):
|
||||||
|
"""
|
||||||
|
Function that cuts off definitions that are too long & strips out UD markdown
|
||||||
|
from an input string.
|
||||||
|
:param text: the input string to clean up
|
||||||
|
:return: the edited version of the string
|
||||||
|
"""
|
||||||
|
text = text.replace("[", "")
|
||||||
|
text = text.replace("]", "")
|
||||||
|
|
||||||
|
if not text:
|
||||||
|
return "N/A"
|
||||||
|
|
||||||
|
return text if len(text) < 1024 else text[:1021] + "..."
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def ratio(dic) -> float:
|
||||||
|
"""
|
||||||
|
Function that calculates the upvote/downvote ratio of the definition.
|
||||||
|
:param dic: the dictionary representing the definition
|
||||||
|
:return: the upvote/downvote ratio (float)
|
||||||
|
"""
|
||||||
|
return (100 * int(dic["thumbs_up"])) / (int(dic["thumbs_up"]) + int(dic["thumbs_down"])) \
|
||||||
|
if int(dic["thumbs_down"]) != 0 else 100.0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def define_didier() -> Dict:
|
||||||
|
"""
|
||||||
|
Function that returns a stock dictionary to define Didier
|
||||||
|
in case people call it, or no definition was found.
|
||||||
|
:return: a dictionary that defines Didier
|
||||||
|
"""
|
||||||
|
return {"word": "Didier", "definition": "Didier", "example": "1: Didier\n2: Hmm?", "thumbs_up": 69420,
|
||||||
|
"thumbs_down": 0, "author": "Didier",
|
||||||
|
"link": "https://upload.wikimedia.org/wikipedia/commons/a/a5"
|
||||||
|
"/Didier_Reynders_in_Iranian_Parliament_02.jpg"}
|
||||||
|
|
||||||
|
def to_embed(self) -> discord.Embed:
|
||||||
|
"""
|
||||||
|
Create an embed for this definition
|
||||||
|
"""
|
||||||
|
# No results found
|
||||||
|
if not self.definition:
|
||||||
|
return self._nothing_found_embed()
|
||||||
|
|
||||||
|
embed = discord.Embed(colour=discord.Colour.from_rgb(220, 255, 0))
|
||||||
|
embed.set_author(name="Urban Dictionary")
|
||||||
|
|
||||||
|
embed.add_field(name="Woord", value=self.definition["word"], inline=True)
|
||||||
|
embed.add_field(name="Auteur", value=self.definition["author"], inline=True)
|
||||||
|
embed.add_field(name="Definitie", value=Definition.clean_string(self.definition["definition"]), inline=False)
|
||||||
|
embed.add_field(name="Voorbeeld", value=Definition.clean_string(self.definition["example"]), inline=False)
|
||||||
|
embed.add_field(name="Rating", value=str(round(Definition.ratio(self.definition), 2)) + "%")
|
||||||
|
embed.add_field(name="Link naar de volledige definitie",
|
||||||
|
value="[Urban Dictionary]({})".format(str(self.definition["link"])))
|
||||||
|
|
||||||
|
return embed
|
||||||
|
|
||||||
|
def _nothing_found_embed(self) -> discord.Embed:
|
||||||
|
"""
|
||||||
|
Special embed when no results could be found
|
||||||
|
"""
|
||||||
|
embed = discord.Embed(colour=discord.Colour.red(), title=self.query[:256])
|
||||||
|
embed.set_author(name="Urban Dictionary")
|
||||||
|
embed.description = "Geen resultaten gevonden"
|
||||||
|
|
||||||
|
return embed
|
|
@ -1,18 +1,23 @@
|
||||||
import discord
|
import discord
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from functions.prefixes import get_prefix
|
from functions.prefixes import get_prefix
|
||||||
from settings import TOKEN
|
from settings import STATUS_MESSAGE, TOKEN
|
||||||
from startup.didier import Didier
|
from startup.didier import Didier
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
load_dotenv(verbose=True)
|
load_dotenv(verbose=True)
|
||||||
|
|
||||||
|
# Activities
|
||||||
|
activity = discord.Activity(type=discord.ActivityType.playing, name=STATUS_MESSAGE)
|
||||||
|
status = discord.Status.online
|
||||||
|
|
||||||
# Configure intents (1.5.0)
|
# Configure intents (1.5.0)
|
||||||
intents = discord.Intents.default()
|
intents = discord.Intents.default()
|
||||||
intents.members = True
|
intents.members = True
|
||||||
|
|
||||||
client = Didier(command_prefix=get_prefix, case_insensitive=True, intents=intents)
|
client = Didier(command_prefix=get_prefix, case_insensitive=True, intents=intents, activity=activity, status=status)
|
||||||
|
|
||||||
|
# Run IPC server if necessary
|
||||||
if client.ipc is not None:
|
if client.ipc is not None:
|
||||||
client.ipc.start()
|
client.ipc.start()
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
"jpl table": "De huidige stand van het klassement.",
|
"jpl table": "De huidige stand van het klassement.",
|
||||||
"jpl update": "Haalt de nieuwe code voor de competitie van dit jaar op.",
|
"jpl update": "Haalt de nieuwe code voor de competitie van dit jaar op.",
|
||||||
"leaderboard": "Bekijk de Top 10 van [Categorie].\nIndien je geen categorie opgeeft krijg je een lijst van categorieën.",
|
"leaderboard": "Bekijk de Top 10 van [Categorie].\nIndien je geen categorie opgeeft krijg je een lijst van categorieën.",
|
||||||
"les": "Bekijk het lessenrooster voor [Dag] in het [Jaargang]-de jaar.\nIndien je geen dag opgeeft, is dit standaard vandaag. De jaargang is standaard 2.\nLes Morgen/Overmorgen werkt ook.",
|
"les": "Bekijk het lessenrooster voor [Dag].\nIndien je geen dag opgeeft, is dit standaard vandaag.\nLes Morgen/Overmorgen werkt ook.",
|
||||||
"lmgtfy": "Stuur iemand een LMGTFY link wanneer ze je een domme vraag stellen in plaats van het zelf op te zoeken.\nQueries met spaties moeten **niet** tussen aanhalingstekens staan.",
|
"lmgtfy": "Stuur iemand een LMGTFY link wanneer ze je een domme vraag stellen in plaats van het zelf op te zoeken.\nQueries met spaties moeten **niet** tussen aanhalingstekens staan.",
|
||||||
"load": "Laadt [Cog] in.",
|
"load": "Laadt [Cog] in.",
|
||||||
"load all": "Laadt alle cogs in.",
|
"load all": "Laadt alle cogs in.",
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
import math
|
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import utils, Member, User
|
|
||||||
from discord.ext import commands
|
|
||||||
from data import constants
|
from data import constants
|
||||||
import requests
|
import requests
|
||||||
from functions.database import currency
|
from functions.database import currency
|
||||||
|
|
|
@ -1,23 +1,20 @@
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
from functions.database import utils
|
from functions.database import utils
|
||||||
|
from functions.stringFormatters import leading_zero as lz
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
def invoked():
|
class InvocationType(IntEnum):
|
||||||
|
TextCommand = 0
|
||||||
|
SlashCommand = 1
|
||||||
|
ContextMenu = 2
|
||||||
|
|
||||||
|
|
||||||
|
def invoked(inv: InvocationType):
|
||||||
t = time.localtime()
|
t = time.localtime()
|
||||||
day_string: str = f"{t.tm_year}-{_lz(t.tm_mon)}-{_lz(t.tm_mday)}"
|
day_string: str = f"{t.tm_year}-{lz(t.tm_mon)}-{lz(t.tm_mday)}"
|
||||||
_update(day_string)
|
_update(day_string, inv)
|
||||||
|
|
||||||
|
|
||||||
def _lz(arg: int) -> str:
|
|
||||||
"""
|
|
||||||
Add leading zeroes if necessary (YYYY-MM-DD)
|
|
||||||
"""
|
|
||||||
arg = str(arg)
|
|
||||||
|
|
||||||
if len(arg) == 1:
|
|
||||||
return f"0{arg}"
|
|
||||||
|
|
||||||
return arg
|
|
||||||
|
|
||||||
|
|
||||||
def _is_present(date: str) -> bool:
|
def _is_present(date: str) -> bool:
|
||||||
|
@ -43,25 +40,27 @@ def _add_date(date: str):
|
||||||
connection = utils.connect()
|
connection = utils.connect()
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
cursor.execute("INSERT INTO command_stats(day, amount) VALUES (%s, 1)", (date,))
|
cursor.execute("INSERT INTO command_stats(day, commands, slash_commands, context_menus) VALUES (%s, 0, 0, 0)", (date,))
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
|
||||||
|
|
||||||
def _update(date: str):
|
def _update(date: str, inv: InvocationType):
|
||||||
"""
|
"""
|
||||||
Increase the counter for a given day
|
Increase the counter for a given day
|
||||||
"""
|
"""
|
||||||
# Date wasn't present yet, add it with a value of 1
|
# Date wasn't present yet, add it
|
||||||
if not _is_present(date):
|
if not _is_present(date):
|
||||||
_add_date(date)
|
_add_date(date)
|
||||||
return
|
|
||||||
|
|
||||||
connection = utils.connect()
|
connection = utils.connect()
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
cursor.execute("""
|
column_name = ["commands", "slash_commands", "context_menus"][inv.value]
|
||||||
|
|
||||||
|
# String formatting is safe here because the input comes from above ^
|
||||||
|
cursor.execute(f"""
|
||||||
UPDATE command_stats
|
UPDATE command_stats
|
||||||
SET amount = amount + 1
|
SET {column_name} = {column_name} + 1
|
||||||
WHERE day = %s
|
WHERE day = %s
|
||||||
""", (date,))
|
""", (date,))
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import requests
|
import requests
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def etenScript(weekDag):
|
def etenScript(weekDag, resto: str = "sterre"):
|
||||||
# What day
|
# What day
|
||||||
weekdagen = ('ma', 'di', 'wo', 'do', 'vr', 'za', 'zo')
|
weekdagen = ('ma', 'di', 'wo', 'do', 'vr', 'za', 'zo')
|
||||||
deltas = {'morgen': 1,
|
deltas = {'morgen': 1,
|
||||||
|
@ -26,7 +23,7 @@ def etenScript(weekDag):
|
||||||
|
|
||||||
# Fetch from API
|
# Fetch from API
|
||||||
try:
|
try:
|
||||||
menu = requests.get(f"https://zeus.ugent.be/hydra/api/2.0/resto/menu/nl-sterre/{d.year}/{d.month}/{d.day}.json").json()
|
menu = requests.get(f"https://zeus.ugent.be/hydra/api/2.0/resto/menu/nl-{resto}/{d.year}/{d.month}/{d.day}.json").json()
|
||||||
|
|
||||||
if not menu["meals"]:
|
if not menu["meals"]:
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
|
@ -5,7 +5,7 @@ from datetime import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from functions.timeFormatters import fromString
|
from functions.timeFormatters import fromString
|
||||||
from functions.scrapers.sporza import getJPLMatches, getJPLTable
|
from functions.scrapers.sporza import getJPLMatches, getJPLTable
|
||||||
from functions.stringFormatters import leadingZero
|
from functions.stringFormatters import leading_zero
|
||||||
import re
|
import re
|
||||||
from requests import get
|
from requests import get
|
||||||
import tabulate
|
import tabulate
|
||||||
|
@ -39,11 +39,11 @@ class Match:
|
||||||
Parse class attributes out of a dictionary returned from an API request
|
Parse class attributes out of a dictionary returned from an API request
|
||||||
"""
|
"""
|
||||||
# The API isn't public, so every single game state is differently formatted
|
# The API isn't public, so every single game state is differently formatted
|
||||||
self.status = self._getStatus(self.matchDict[Navigation.Status.value])
|
self.status = self._get_status(self.matchDict[Navigation.Status.value])
|
||||||
self.home = self.matchDict[Navigation.HomeTeam.value][Navigation.Name.value]
|
self.home = self.matchDict[Navigation.HomeTeam.value][Navigation.Name.value]
|
||||||
self.away = self.matchDict[Navigation.AwayTeam.value][Navigation.Name.value]
|
self.away = self.matchDict[Navigation.AwayTeam.value][Navigation.Name.value]
|
||||||
|
|
||||||
if self._hasStarted():
|
if self._has_started():
|
||||||
self.homeScore = self.matchDict[Navigation.HomeScore.value]
|
self.homeScore = self.matchDict[Navigation.HomeScore.value]
|
||||||
self.awayScore = self.matchDict[Navigation.AwayScore.value]
|
self.awayScore = self.matchDict[Navigation.AwayScore.value]
|
||||||
|
|
||||||
|
@ -53,9 +53,9 @@ class Match:
|
||||||
self.start = None
|
self.start = None
|
||||||
|
|
||||||
self.date = self.start.strftime("%d/%m") if self.start is not None else "Uitgesteld"
|
self.date = self.start.strftime("%d/%m") if self.start is not None else "Uitgesteld"
|
||||||
self.weekDay = self._getWeekday() if self.start is not None else "??"
|
self.weekDay = self._get_weekday() if self.start is not None else "??"
|
||||||
|
|
||||||
def _getStatus(self, status: str):
|
def _get_status(self, status: str):
|
||||||
"""
|
"""
|
||||||
Gets the string representation for the status of this match
|
Gets the string representation for the status of this match
|
||||||
"""
|
"""
|
||||||
|
@ -80,7 +80,7 @@ class Match:
|
||||||
|
|
||||||
return statusses[status.lower()]
|
return statusses[status.lower()]
|
||||||
|
|
||||||
def _getWeekday(self):
|
def _get_weekday(self):
|
||||||
"""
|
"""
|
||||||
Gets the day of the week this match is played on
|
Gets the day of the week this match is played on
|
||||||
"""
|
"""
|
||||||
|
@ -88,13 +88,13 @@ class Match:
|
||||||
days = ["Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"]
|
days = ["Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"]
|
||||||
return days[day]
|
return days[day]
|
||||||
|
|
||||||
def getInfo(self):
|
def get_info(self):
|
||||||
"""
|
"""
|
||||||
Returns a list of all the info of this class in order to create a table
|
Returns a list of all the info of this class in order to create a table
|
||||||
"""
|
"""
|
||||||
return [self.weekDay, self.date, self.home, self._getScore(), self.away, self.status]
|
return [self.weekDay, self.date, self.home, self._get_score(), self.away, self.status]
|
||||||
|
|
||||||
def _getScore(self):
|
def _get_score(self):
|
||||||
"""
|
"""
|
||||||
Returns a string representing the scoreboard
|
Returns a string representing the scoreboard
|
||||||
"""
|
"""
|
||||||
|
@ -102,12 +102,12 @@ class Match:
|
||||||
return "??"
|
return "??"
|
||||||
|
|
||||||
# No score to show yet, show time when the match starts
|
# No score to show yet, show time when the match starts
|
||||||
if not self._hasStarted():
|
if not self._has_started():
|
||||||
return "{}:{}".format(leadingZero(str(self.start.hour)), leadingZero(str(self.start.minute)))
|
return "{}:{}".format(leading_zero(str(self.start.hour)), leading_zero(str(self.start.minute)))
|
||||||
|
|
||||||
return "{} - {}".format(self.homeScore, self.awayScore)
|
return "{} - {}".format(self.homeScore, self.awayScore)
|
||||||
|
|
||||||
def _hasStarted(self):
|
def _has_started(self):
|
||||||
return self.status not in [Status.AfterToday.value, Status.NotStarted.value, Status.Postponed.value]
|
return self.status not in [Status.AfterToday.value, Status.NotStarted.value, Status.Postponed.value]
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ class Navigation(Enum):
|
||||||
Name = "name"
|
Name = "name"
|
||||||
|
|
||||||
|
|
||||||
def getMatches(matchweek: int):
|
def get_matches(matchweek: int):
|
||||||
"""
|
"""
|
||||||
Function that constructs the list of matches for a given matchweek
|
Function that constructs the list of matches for a given matchweek
|
||||||
"""
|
"""
|
||||||
|
@ -139,7 +139,7 @@ def getMatches(matchweek: int):
|
||||||
return "Er ging iets fout. Probeer het later opnieuw."
|
return "Er ging iets fout. Probeer het later opnieuw."
|
||||||
|
|
||||||
matches = list(map(Match, current_day))
|
matches = list(map(Match, current_day))
|
||||||
matches = list(map(lambda x: x.getInfo(), matches))
|
matches = list(map(lambda x: x.get_info(), matches))
|
||||||
|
|
||||||
header = "Jupiler Pro League - Speeldag {}".format(matchweek)
|
header = "Jupiler Pro League - Speeldag {}".format(matchweek)
|
||||||
table = tabulate.tabulate(matches, headers=["Dag", "Datum", "Thuis", "Stand", "Uit", "Tijd"])
|
table = tabulate.tabulate(matches, headers=["Dag", "Datum", "Thuis", "Stand", "Uit", "Tijd"])
|
||||||
|
@ -147,7 +147,7 @@ def getMatches(matchweek: int):
|
||||||
return "```{}\n\n{}```".format(header, table)
|
return "```{}\n\n{}```".format(header, table)
|
||||||
|
|
||||||
|
|
||||||
def getTable():
|
def get_table():
|
||||||
"""
|
"""
|
||||||
Function that constructs the current table of the JPL
|
Function that constructs the current table of the JPL
|
||||||
"""
|
"""
|
||||||
|
@ -157,7 +157,7 @@ def getTable():
|
||||||
return "Er ging iets fout. Probeer het later opnieuw."
|
return "Er ging iets fout. Probeer het later opnieuw."
|
||||||
|
|
||||||
# Format every row to work for Tabulate
|
# Format every row to work for Tabulate
|
||||||
formatted = [_formatRow(row) for row in rows]
|
formatted = [_format_row(row) for row in rows]
|
||||||
|
|
||||||
header = "Jupiler Pro League Klassement"
|
header = "Jupiler Pro League Klassement"
|
||||||
table = tabulate.tabulate(formatted, headers=["#", "Ploeg", "Punten", "M", "M+", "M-", "M=", "D+", "D-", "D+/-"])
|
table = tabulate.tabulate(formatted, headers=["#", "Ploeg", "Punten", "M", "M+", "M-", "M=", "D+", "D-", "D+/-"])
|
||||||
|
@ -165,7 +165,7 @@ def getTable():
|
||||||
return "```{}\n\n{}```".format(header, table)
|
return "```{}\n\n{}```".format(header, table)
|
||||||
|
|
||||||
|
|
||||||
def _formatRow(row):
|
def _format_row(row):
|
||||||
"""
|
"""
|
||||||
Function that formats a row into a list for Tabulate to use
|
Function that formats a row into a list for Tabulate to use
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,9 +1,23 @@
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
import discord
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
from dataclasses import dataclass
|
||||||
from requests import get
|
from requests import get
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode, unquote_plus
|
||||||
|
|
||||||
|
|
||||||
def google_search(query):
|
@dataclass
|
||||||
|
class SearchResult:
|
||||||
|
status_code: int
|
||||||
|
query: str
|
||||||
|
results: List[str]
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
self.query = unquote_plus(self.query[2:])
|
||||||
|
|
||||||
|
|
||||||
|
def google_search(query) -> SearchResult:
|
||||||
"""
|
"""
|
||||||
Function to get Google search results
|
Function to get Google search results
|
||||||
"""
|
"""
|
||||||
|
@ -17,7 +31,7 @@ def google_search(query):
|
||||||
resp = get("https://www.google.com/search?{}&num=20&hl=en".format(query), headers=headers)
|
resp = get("https://www.google.com/search?{}&num=20&hl=en".format(query), headers=headers)
|
||||||
|
|
||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
return None, resp.status_code
|
return SearchResult(resp.status_code, query, [])
|
||||||
|
|
||||||
bs = BeautifulSoup(resp.text, "html.parser")
|
bs = BeautifulSoup(resp.text, "html.parser")
|
||||||
|
|
||||||
|
@ -28,11 +42,48 @@ def google_search(query):
|
||||||
link = element.find("a", href=True)
|
link = element.find("a", href=True)
|
||||||
title = element.find("h3")
|
title = element.find("h3")
|
||||||
|
|
||||||
if link is None or title is None:
|
if link is None or not link["href"].startswith(("http://", "https://",)) or title is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return link["href"], title.text
|
return link["href"], title.text
|
||||||
|
|
||||||
divs = bs.find_all("div", attrs={"class": "g"})
|
divs = bs.find_all("div", attrs={"class": "g"})
|
||||||
|
|
||||||
return list(getContent(d) for d in divs), 200
|
results = list(getContent(d) for d in divs)
|
||||||
|
|
||||||
|
# Filter out Nones
|
||||||
|
results = list(filter(lambda x: x is not None, results))
|
||||||
|
|
||||||
|
# Map to urls
|
||||||
|
links = []
|
||||||
|
for (l, t) in results:
|
||||||
|
links.append(f"[{t}]({l})")
|
||||||
|
|
||||||
|
return SearchResult(200, query, links[:10])
|
||||||
|
|
||||||
|
|
||||||
|
def create_google_embed(result: SearchResult) -> discord.Embed:
|
||||||
|
embed = discord.Embed(colour=discord.Colour.blue())
|
||||||
|
embed.set_author(name="Google Search")
|
||||||
|
|
||||||
|
# Empty list of results
|
||||||
|
if len(result.results) == 0:
|
||||||
|
embed.colour = discord.Colour.red()
|
||||||
|
embed.description = "Geen resultaten gevonden."
|
||||||
|
return embed
|
||||||
|
|
||||||
|
# Add results into a field
|
||||||
|
links = []
|
||||||
|
|
||||||
|
for index, link in enumerate(result.results):
|
||||||
|
links.append(f"{index + 1}: {link}")
|
||||||
|
|
||||||
|
embed.description = "\n".join(links)
|
||||||
|
|
||||||
|
# Add query into embed
|
||||||
|
if len(result.query) > 256:
|
||||||
|
embed.title = result.query[:253] + "..."
|
||||||
|
else:
|
||||||
|
embed.title = result.query
|
||||||
|
|
||||||
|
return embed
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
def titleCase(string):
|
import traceback
|
||||||
|
|
||||||
|
from discord.ext.commands import Context
|
||||||
|
from dislash import SlashInteraction
|
||||||
|
|
||||||
|
|
||||||
|
def title_case(string):
|
||||||
return " ".join(capitalize(word) for word in string.split(" "))
|
return " ".join(capitalize(word) for word in string.split(" "))
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,8 +14,40 @@ def capitalize(string):
|
||||||
return string[0].upper()
|
return string[0].upper()
|
||||||
|
|
||||||
|
|
||||||
def leadingZero(string, size=2):
|
def leading_zero(string, size=2):
|
||||||
string = str(string)
|
string = str(string)
|
||||||
while len(string) < size:
|
while len(string) < size:
|
||||||
string = "0" + string
|
string = "0" + string
|
||||||
return string
|
return string
|
||||||
|
|
||||||
|
|
||||||
|
def format_error_tb(err: Exception) -> str:
|
||||||
|
# Remove the InvokeCommandError because it's useless information
|
||||||
|
x = traceback.format_exception(type(err), err, err.__traceback__)
|
||||||
|
error_string = ""
|
||||||
|
for line in x:
|
||||||
|
if "direct cause of the following" in line:
|
||||||
|
break
|
||||||
|
error_string += line.replace("*", "") + "\n" if line.strip() != "" else ""
|
||||||
|
|
||||||
|
return error_string
|
||||||
|
|
||||||
|
|
||||||
|
def _format_error_location(src) -> str:
|
||||||
|
DM = src.guild is None
|
||||||
|
return "DM" if DM else f"{src.channel.name} ({src.guild.name})"
|
||||||
|
|
||||||
|
|
||||||
|
def format_command_usage(ctx: Context) -> str:
|
||||||
|
return f"{ctx.author.display_name} in {_format_error_location(ctx)}: {ctx.message.content}"
|
||||||
|
|
||||||
|
|
||||||
|
def format_slash_command_usage(interaction: SlashInteraction) -> str:
|
||||||
|
# Create a string with the options used
|
||||||
|
options = " ".join(list(map(
|
||||||
|
lambda option: f"{option.name}: \"{option.value}\"",
|
||||||
|
interaction.data.options.values()
|
||||||
|
)))
|
||||||
|
|
||||||
|
command = f"{interaction.slash_command.name} {options or ''}"
|
||||||
|
return f"{interaction.author.display_name} in {_format_error_location(interaction)}: /{command}"
|
||||||
|
|
|
@ -161,14 +161,14 @@ def fromString(timeString: str, formatString="%d/%m/%Y", tzinfo=pytz.timezone("E
|
||||||
|
|
||||||
|
|
||||||
def fromArray(data: List[int]) -> datetime:
|
def fromArray(data: List[int]) -> datetime:
|
||||||
day = stringFormatters.leadingZero(str(data[0]))
|
day = stringFormatters.leading_zero(str(data[0]))
|
||||||
month = stringFormatters.leadingZero(str(data[1]))
|
month = stringFormatters.leading_zero(str(data[1]))
|
||||||
year = str(data[2])
|
year = str(data[2])
|
||||||
|
|
||||||
if len(data) == 6:
|
if len(data) == 6:
|
||||||
hour = stringFormatters.leadingZero(str(data[3]))
|
hour = stringFormatters.leading_zero(str(data[3]))
|
||||||
minute = stringFormatters.leadingZero(str(data[4]))
|
minute = stringFormatters.leading_zero(str(data[4]))
|
||||||
second = stringFormatters.leadingZero(str(data[5]))
|
second = stringFormatters.leading_zero(str(data[5]))
|
||||||
|
|
||||||
return fromString(f"{day}/{month}/{year} {hour}:{minute}:{second}", formatString="%d/%m/%Y %H:%M:%S")
|
return fromString(f"{day}/{month}/{year} {hour}:{minute}:{second}", formatString="%d/%m/%Y %H:%M:%S")
|
||||||
|
|
||||||
|
|
|
@ -19,3 +19,6 @@ attrs~=21.2.0
|
||||||
dacite~=1.6.0
|
dacite~=1.6.0
|
||||||
pytest==6.2.4
|
pytest==6.2.4
|
||||||
markdownify==0.9.2
|
markdownify==0.9.2
|
||||||
|
|
||||||
|
# Experimental package for slash commands & menus
|
||||||
|
dislash.py==1.4.9
|
10
settings.py
10
settings.py
|
@ -1,3 +1,5 @@
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -31,3 +33,11 @@ TOKEN = os.getenv("TOKEN", "")
|
||||||
HOST_IPC = _to_bool(os.getenv("HOSTIPC", "false"))
|
HOST_IPC = _to_bool(os.getenv("HOSTIPC", "false"))
|
||||||
READY_MESSAGE = os.getenv("READYMESSAGE", "I'M READY I'M READY I'M READY I'M READY") # Yes, this is a Spongebob reference
|
READY_MESSAGE = os.getenv("READYMESSAGE", "I'M READY I'M READY I'M READY I'M READY") # Yes, this is a Spongebob reference
|
||||||
STATUS_MESSAGE = os.getenv("STATUSMESSAGE", "with your Didier Dinks.")
|
STATUS_MESSAGE = os.getenv("STATUSMESSAGE", "with your Didier Dinks.")
|
||||||
|
|
||||||
|
# Guilds to test slash commands in
|
||||||
|
# Ex: 123,456,789
|
||||||
|
SLASH_TEST_GUILDS: List[int] = list(
|
||||||
|
map(lambda x: int(x),
|
||||||
|
os.getenv("SLASHTESTGUILDS", "").replace(" ", "").split(",")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from data.snipe import Snipe
|
from data.snipe import Snipe
|
||||||
from discord.ext import commands, ipc
|
from discord.ext import commands, ipc
|
||||||
|
from dislash import InteractionClient
|
||||||
import os
|
import os
|
||||||
from settings import HOST_IPC
|
from settings import HOST_IPC, SLASH_TEST_GUILDS
|
||||||
from startup.init_files import check_all
|
from startup.init_files import check_all
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
|
@ -10,6 +11,8 @@ class Didier(commands.Bot):
|
||||||
"""
|
"""
|
||||||
Main Bot class for Didier
|
Main Bot class for Didier
|
||||||
"""
|
"""
|
||||||
|
# Reference to interactions client
|
||||||
|
interactions: InteractionClient
|
||||||
|
|
||||||
# Dict to store the most recent Snipe info per channel
|
# Dict to store the most recent Snipe info per channel
|
||||||
snipe: Dict[int, Snipe] = {}
|
snipe: Dict[int, Snipe] = {}
|
||||||
|
@ -29,6 +32,9 @@ class Didier(commands.Bot):
|
||||||
# Remove default help command
|
# Remove default help command
|
||||||
self.remove_command("help")
|
self.remove_command("help")
|
||||||
|
|
||||||
|
# Create interactions client
|
||||||
|
self.interactions = InteractionClient(self, test_guilds=SLASH_TEST_GUILDS)
|
||||||
|
|
||||||
# Load all extensions
|
# Load all extensions
|
||||||
self.init_extensions()
|
self.init_extensions()
|
||||||
|
|
||||||
|
@ -41,9 +47,24 @@ class Didier(commands.Bot):
|
||||||
self.load_extension(f"cogs.{ext}")
|
self.load_extension(f"cogs.{ext}")
|
||||||
|
|
||||||
# Load all remaining cogs
|
# Load all remaining cogs
|
||||||
for file in os.listdir("./cogs"):
|
self._init_directory("./cogs")
|
||||||
if file.endswith(".py") and not (file.startswith(self._preload)):
|
|
||||||
self.load_extension("cogs.{}".format(file[:-3]))
|
def _init_directory(self, path: str):
|
||||||
|
"""
|
||||||
|
Load all cogs from a directory
|
||||||
|
"""
|
||||||
|
# Path to pass into load_extension
|
||||||
|
load_path = path[2:].replace("/", ".")
|
||||||
|
|
||||||
|
for file in os.listdir(path):
|
||||||
|
# Python file
|
||||||
|
if file.endswith(".py"):
|
||||||
|
if not file.startswith(self._preload):
|
||||||
|
self.load_extension(f"{load_path}.{file[:-3]}")
|
||||||
|
elif os.path.isdir(new_path := f"{path}/{file}"):
|
||||||
|
# Subdirectory
|
||||||
|
# Also walrus operator hype
|
||||||
|
self._init_directory(new_path)
|
||||||
|
|
||||||
async def on_ipc_ready(self):
|
async def on_ipc_ready(self):
|
||||||
print("IPC server is ready.")
|
print("IPC server is ready.")
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
from data.embeds.urban_dictionary import Definition
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class TestUD(unittest.TestCase):
|
||||||
|
def test_clean_string(self):
|
||||||
|
self.assertEqual(
|
||||||
|
Definition.clean_string("A definition [with links] to other [definitions]"),
|
||||||
|
"A definition with links to other definitions"
|
||||||
|
)
|
||||||
|
|
||||||
|
no_processing = "A string that needs no processing."
|
||||||
|
self.assertEqual(Definition.clean_string(no_processing), no_processing)
|
||||||
|
|
||||||
|
long_string = "A very long string that hopefully exceeds the 1024 character limit for embed field values, " \
|
||||||
|
"in order to test if the truncation part of this specific function works as expected. " \
|
||||||
|
"The issue is that coming up with a string that exceeds the 1024 embed field value character " \
|
||||||
|
"limit is quite tedious, so I have no idea how I plan on ever finishing this." \
|
||||||
|
"As of the writing of this sentence, I'm only a third of the way there." \
|
||||||
|
"Crazy. I could probably just toss some lorem ipsum in there, but that would be no fun." \
|
||||||
|
"Or would it? Hey GitHub, Didier here." \
|
||||||
|
"Instead I would like to take this opportunity to out my frustrations on the abomination of a " \
|
||||||
|
"\"language\" that is Haskell. You see, Haskell is just terrible and useless. " \
|
||||||
|
"It truly does pose the bane of my existence, and I deeply hope that I will never have to use it " \
|
||||||
|
"ever again in my life. Good thing I somehow managed to pass that class, otherwise I would've " \
|
||||||
|
"probably collapsed mentally on the spot. As it turns out, though, this sentence is already in the " \
|
||||||
|
"900 character range, so I don't have much of a reason to continue writing about the worst " \
|
||||||
|
"invention humanity has ever come up with."
|
||||||
|
|
||||||
|
self.assertGreater(len(long_string), 1024)
|
||||||
|
self.assertEqual(len(Definition.clean_string(long_string)), 1024)
|
||||||
|
self.assertEqual(Definition.clean_string(long_string)[-3:], "...")
|
||||||
|
|
||||||
|
def test_ratio(self):
|
||||||
|
dic = {
|
||||||
|
"thumbs_up": 5,
|
||||||
|
"thumbs_down": 0
|
||||||
|
}
|
||||||
|
self.assertEqual(Definition.ratio(dic), 100.0)
|
||||||
|
|
||||||
|
dic["thumbs_down"] = 5
|
||||||
|
self.assertEqual(Definition.ratio(dic), 50.0)
|
||||||
|
|
||||||
|
dic["thumbs_up"] = 0
|
||||||
|
self.assertEqual(Definition.ratio(dic), 0)
|
Loading…
Reference in New Issue