Merge pull request #108 from stijndcl/compbio_commands

Add commands to track compbio leaderboards
pull/136/head
Stijn De Clercq 2022-03-11 14:17:12 +01:00 committed by GitHub
commit 635560dcd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 123 additions and 17 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ files/stats.json
files/lost.json
files/locked.json
files/ufora_notifications.json
files/compbio_benchmarks_2.json
.idea/
__pycache__
.env

View File

@ -1,3 +1,6 @@
import json
from discord import SlashCommandGroup
from discord.ext import commands
from discord.commands import slash_command, ApplicationContext, Option, AutocompleteContext
@ -5,6 +8,7 @@ from data import schedule
from data.courses import load_courses, find_course_from_name
from data.embeds.food import Menu
from data.embeds.deadlines import Deadlines
from data.menus import leaderboards
from functions import les, config
from functions.stringFormatters import capitalize
from functions.timeFormatters import skip_weekends
@ -83,6 +87,30 @@ class SchoolSlash(commands.Cog):
year = 2018 + int(config.get("year"))
return await ctx.respond(f"https://studiekiezer.ugent.be/studiefiche/nl/{course.code}/{year}")
_compbio_group = SlashCommandGroup("compbio", "Commands voor compbio opdrachten")
@_compbio_group.command(name="leaderboard", description="Gesorteerd en ingevuld leaderboard")
async def _compbio_lb_slash(self, ctx: ApplicationContext):
lb = leaderboards.CompbioLeaderboard(ctx)
await lb.respond()
@_compbio_group.command(name="submit", description="Link een Dodona-submission aan jouw username")
async def _compbio_submit_slash(self, ctx: ApplicationContext,
submission: Option(int, description="Id van je Dodona indiening.", required=True)):
with open("files/compbio_benchmarks_2.json", "r") as fp:
file = json.load(fp)
submission = str(submission)
if submission in file:
return await ctx.respond("❌ Deze submission is al aan iemand gelinkt.", ephemeral=True)
with open("files/compbio_benchmarks_2.json", "w") as fp:
file[submission] = ctx.user.id
json.dump(file, fp)
return await ctx.respond(f"✅ Submission **{submission}** is aan jouw naam gelinkt.", ephemeral=True)
def setup(client: Didier):
client.add_cog(SchoolSlash(client))

View File

@ -1,3 +1,4 @@
import json
import math
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
@ -8,11 +9,12 @@ import requests
from discord import ApplicationContext
from discord.ext.commands import Context
import settings
from data.menus.paginated import Paginated
from enums.numbers import Numbers
from functions import xp
from functions.database import currency, stats, poke, muttn
from functions.utils import get_display_name
from functions.utils import get_display_name, get_mention
@dataclass
@ -21,6 +23,7 @@ class Leaderboard(Paginated, ABC):
colour: discord.Colour = discord.Colour.blue()
fetch_names: bool = True
ignore_non_pos: bool = True
reverse: bool = True
def __post_init__(self):
self.data = self.process_data(self.get_data())
@ -31,7 +34,7 @@ class Leaderboard(Paginated, ABC):
def process_data(self, entries: list[tuple]) -> Optional[list[tuple]]:
data = []
for i, v in enumerate(sorted(entries, key=self.get_value, reverse=True)):
for i, v in enumerate(sorted(entries, key=self.get_value, reverse=self.reverse)):
entry_data = self.get_value(v)
# Leaderboard is empty
@ -90,13 +93,13 @@ class Leaderboard(Paginated, ABC):
return await ctx.reply(embed=embed, **kwargs)
async def respond(self, **kwargs) -> discord.Message:
if self.data is None:
if self.data is None or not self.data:
return await self.empty_leaderboard(self.ctx, **kwargs)
return await super().respond(**kwargs)
async def send(self, **kwargs) -> discord.Message:
if self.data is None:
if self.data is None or not self.data:
return await self.empty_leaderboard(self.ctx, **kwargs)
return await super().send(**kwargs)
@ -117,6 +120,56 @@ class BitcoinLeaderboard(Leaderboard):
return "Er zijn nog geen personen met Bitcoins."
@dataclass
class CompbioLeaderboard(Leaderboard):
colour: discord.Colour = field(default=discord.Colour.green())
title: str = field(default="Leaderboard Computationele Biologie #2")
reverse: bool = False
def get_submission_user(self, submission_id: str) -> str:
with open("files/compbio_benchmarks_2.json", "r") as fp:
file = json.load(fp)
if submission_id in file:
user_id = file[submission_id]
return get_mention(self.ctx, user_id)
return f"[# {submission_id}]"
def get_data(self) -> list[tuple]:
headers = {"Authorization": f"token {settings.UGENT_GH_TOKEN}"}
result = requests.get(f"https://github.ugent.be/raw/computationele-biologie/benchmarks-2022/main/reconstruction/J02459.1.50mers.md", headers=headers).text
# Remove table headers
result = result.split("\n")[2:]
data = []
for line in result:
try:
cells = line.split("|")
submission_id = cells[1].strip()
mean = float(cells[2].strip().split(" ")[0])
except IndexError:
# Other lines because of markdown formatting
continue
data.append((submission_id, mean, ))
return data
def _should_highlight(self, data) -> bool:
# TODO maybe find a fix for this?
return False
def format_entry(self, index: int, data: tuple) -> str:
return f"{index + 1}: {self.get_submission_user(data[0])} ({self.format_entry_data(data)})"
def format_entry_data(self, data: tuple) -> str:
return f"{str(data[1])} ms"
def get_value(self, data: tuple):
return data[1]
@dataclass
class CoronaLeaderboard(Leaderboard):
colour: discord.Colour = field(default=discord.Colour.red())

View File

@ -45,7 +45,7 @@ def format_command_usage(ctx: Context) -> str:
def format_slash_command_usage(interaction: Interaction) -> str:
# Create a string with the options used
options = " ".join(list(map(
lambda o: f"{o['name']}: \"{o['value']}\"",
lambda o: f"{o['name']}: \"{o['value']}\"" if "value" in o else o["name"],
interaction.data.get("options", [])
)))

View File

@ -4,34 +4,55 @@ import discord
from discord import ApplicationContext
from discord.ext.commands import Context
from data import constants
import settings
def get_display_name(ctx: Union[ApplicationContext, Context], user_id: int) -> str:
def get_member_or_user(ctx: Union[ApplicationContext, Context], user_id: int) -> Optional[Union[discord.Member, discord.User]]:
"""Get a COC Member instance of a user if they are in the server,
otherwise the regular User instance
"""
author = ctx.author if isinstance(ctx, Context) else ctx.user
# Check if this is a DM, or the user is not in the guild
if ctx.guild is None or ctx.guild.get_member(user_id) is None:
# User is the author, no need to fetch their name
if user_id == author.id:
return author.display_name
return author
# Get member instance from CoC
COC = ctx.bot.get_guild(int(constants.DeZandbak))
COC = ctx.bot.get_guild(settings.COC_ID)
member = COC.get_member(user_id)
if member is not None:
return member.display_name
return member
# Try to fetch the user
user = ctx.bot.get_user(user_id)
if user is not None:
return user.name
return ctx.bot.get_user(user_id)
# User couldn't be found
# Guild exists, use that instead
return ctx.guild.get_member(user_id)
def get_display_name(ctx: Union[ApplicationContext, Context], user_id: int) -> str:
member = get_member_or_user(ctx, user_id)
# Nothing found
if member is None:
return f"[? | {user_id}]"
mem = ctx.guild.get_member(user_id)
return mem.display_name
if isinstance(member, discord.Member):
return member.display_name
return member.name
def get_mention(ctx: Union[ApplicationContext, Context], user_id: int) -> str:
member = get_member_or_user(ctx, user_id)
# Nothing found
if member is None:
return f"[? | {user_id}]"
return member.mention
async def reply_to_reference(ctx: Context, content: Optional[str] = None, embed: Optional[discord.Embed] = None, always_mention=False):

View File

@ -1,5 +1,5 @@
# Beta version of Discord.py fork
py-cord==2.0.0b1
py-cord==2.0.0b5
python-dotenv==0.14.0
beautifulsoup4==4.9.1

View File

@ -41,3 +41,6 @@ COC_ID: int = int(os.getenv("COC_ID", "626699611192688641"))
# Ex: 123,456,789
_guilds = os.getenv("SLASHTESTGUILDS", "").replace(" ", "")
SLASH_TEST_GUILDS: List[int] = list(map(lambda x: int(x), _guilds.split(","))) if _guilds else None
# GitHub token (UGent)
UGENT_GH_TOKEN = os.getenv("UGENTGHTOKEN", "")