diff --git a/src/cogs/dev.py b/src/cogs/dev.py index 2024094..b0e5249 100644 --- a/src/cogs/dev.py +++ b/src/cogs/dev.py @@ -47,6 +47,9 @@ class DevCog(Cog, name="Dev tools"): # Utility functions def send(msg, channel=None): + if isinstance(channel, int): + channel = get(ctx.guild.channels, id=channel) + channel = channel or ctx.channel asyncio.create_task(channel.send(msg)) diff --git a/src/cogs/misc.py b/src/cogs/misc.py index 81ab1a1..08de124 100644 --- a/src/cogs/misc.py +++ b/src/cogs/misc.py @@ -2,11 +2,14 @@ import datetime import io import itertools import random +from dataclasses import dataclass, field from operator import attrgetter from time import time +from typing import List, Set import aiohttp import discord +import yaml from discord import Guild from discord.ext import commands from discord.ext.commands import ( @@ -16,12 +19,24 @@ from discord.ext.commands import ( Command, CommandError, Group, + group, ) from src.constants import * from src.constants import Emoji from src.core import CustomBot -from src.utils import has_role, start_time +from src.utils import has_role, start_time, send_and_bin + + +@dataclass +class Joke(yaml.YAMLObject): + yaml_tag = "Joke" + yaml_dumper = yaml.SafeDumper + yaml_loader = yaml.SafeLoader + joke: str + joker: int + likes: Set[int] = field(default_factory=set) + dislikes: Set[int] = field(default_factory=set) class MiscCog(Cog, name="Divers"): @@ -47,19 +62,6 @@ class MiscCog(Cog, name="Divers"): msg = await ctx.send(f"J'ai choisi... **{choice}**") await self.bot.wait_for_bin(ctx.author, msg), - @command(name="joke", aliases=["blague"], hidden=True) - async def joke_cmd(self, ctx): - await ctx.message.delete() - with open(File.JOKES) as f: - jokes = f.read().split("---") - - msg = random.choice(jokes) - message: discord.Message = await ctx.send(msg) - - await message.add_reaction(Emoji.JOY) - await message.add_reaction(Emoji.SOB) - await self.bot.wait_for_bin(ctx.message.author, message) - @command(name="status") @commands.has_role(Role.CNO) async def status_cmd(self, ctx: Context): @@ -70,12 +72,15 @@ class MiscCog(Cog, name="Divers"): participants = [g for g in guild.members if has_role(g, Role.PARTICIPANT)] no_role = [g for g in guild.members if g.top_role == guild.default_role] uptime = datetime.timedelta(seconds=round(time() - start_time())) - + text = len(guild.text_channels) + vocal = len(guild.voice_channels) infos = { "Bénévoles": len(benevoles), "Participants": len(participants), "Sans rôle": len(no_role), "Total": len(guild.members), + "Salons texte": text, + "Salons vocaux": vocal, "Bot uptime": uptime, } @@ -99,6 +104,80 @@ class MiscCog(Cog, name="Divers"): data = io.BytesIO(await resp.read()) await ctx.send(file=discord.File(data, "cool_image.png")) + # ---------------- Jokes ---------------- # + + def load_jokes(self) -> List[Joke]: + # Ensure it exists + File.JOKES_V2.touch() + with open(File.JOKES_V2) as f: + jokes = list(yaml.safe_load_all(f)) + + return jokes + + def save_jokes(self, jokes): + File.JOKES_V2.touch() + with open(File.JOKES_V2, "w") as f: + yaml.safe_dump_all(jokes, f) + + @group(name="joke", hidden=True, invoke_without_command=True) + async def joke(self, ctx): + await ctx.message.delete() + + jokes = self.load_jokes() + joke_id = random.randrange(len(jokes)) + joke = jokes[joke_id] + + message: discord.Message = await ctx.send(joke.joke) + + await message.add_reaction(Emoji.PLUS_1) + await message.add_reaction(Emoji.MINUS_1) + await self.wait_for_joke_reactions(joke_id, message) + + @joke.command(name="new", hidden=True) + @send_and_bin + async def new_joke(self, ctx: Context): + author: discord.Member = ctx.author + message: discord.Message = ctx.message + + start = "!joke new " + msg = message.content[len(start) :] + + joke = Joke(msg, ctx.author.id, set()) + + jokes = self.load_jokes() + jokes.append(joke) + self.save_jokes(jokes) + joke_id = len(jokes) - 1 + await message.add_reaction(Emoji.PLUS_1) + await message.add_reaction(Emoji.MINUS_1) + + await self.wait_for_joke_reactions(joke_id, message) + + async def wait_for_joke_reactions(self, joke_id, message): + def check(reaction: discord.Reaction, u): + return (message.id == reaction.message.id) and str(reaction.emoji) in ( + Emoji.PLUS_1, + Emoji.MINUS_1, + ) + + start = time() + end = start + 24 * 60 * 60 + while time() < end: + reaction, user = await self.bot.wait_for( + "reaction_add", check=check, timeout=end - time() + ) + + if user.id == BOT: + continue + + jokes = self.load_jokes() + if str(reaction.emoji) == Emoji.PLUS_1: + jokes[joke_id].likes.add(user.id) + else: + jokes[joke_id].dislikes.add(user.id) + + self.save_jokes(jokes) + # ----------------- Help ---------------- # @command(name="help", aliases=["h"]) diff --git a/src/cogs/teams.py b/src/cogs/teams.py index 8b89d80..d1273e0 100644 --- a/src/cogs/teams.py +++ b/src/cogs/teams.py @@ -189,17 +189,18 @@ class TeamsCog(Cog, name="Teams"): f"est {ctx.author.mention}" ) - diego = get(ctx.guild.members, display_name=DIEGO, top_role__name=Role.CNO) + diego = get(ctx.guild.members, id=DIEGO) await ctx.author.send( - f"Salut Capitaine !\n" + "Salut Capitaine !\n" "On va être amené à faire de nombreuses choses ensemble " "ces prochains jours, donc n'hésite pas à abuser de `!help`. " "Tu peux l'utiliser ici mais malheureusement tu ne pourra pas voir " "les commandes qui sont réservés aux capitaines. \n" "Une commande que tu peux avoir envie d'utiliser c'est " "`!team channel un-super-nom` pour créer une channel réservée à " - "ton équipe. \n\n" - f"Si tu as des suggestions pour que le bot permette à chacun d'avoir " + "ton équipe. `!team voice un-super-nom` permet " + "aussi de créer un salon vocal :wink: \n\n" + "Si tu as des suggestions pour que le bot permette à chacun d'avoir " f"une meilleure expérience ici, envoie un petit message à {diego.mention} ;)" ) @@ -265,7 +266,7 @@ class TeamsCog(Cog, name="Teams"): if not channel_name: return ( - "Tu dois mettre un nom d'équipe, par exemple " + "Tu dois mettre un nom de salon, par exemple " "`!team channel un-super-nom`" ) @@ -302,7 +303,7 @@ class TeamsCog(Cog, name="Teams"): if not channel_name: return ( - "Tu dois mettre un nom d'équipe, par exemple " + "Tu dois mettre un nom de salon, par exemple " "`!team voice un-super-nom`" ) diff --git a/src/cogs/tirages.py b/src/cogs/tirages.py index 72443b0..db88555 100644 --- a/src/cogs/tirages.py +++ b/src/cogs/tirages.py @@ -845,6 +845,7 @@ class TirageCog(Cog, name="Tirages"): @draw_group.command(name="dump") @commands.has_role(Role.DEV) async def dump_cmd(self, ctx, tirage_id: int, round=0): + """Affiche un résumé succint d'un tirage.""" tirages = self.get_tirages() try: @@ -864,11 +865,6 @@ class TirageCog(Cog, name="Tirages"): await ctx.send(msg) - @draw_group.command() - @commands.has_role(Role.DEV) - async def debug(self, ctx, id: int): - pass - def setup(bot): bot.add_cog(TirageCog(bot)) diff --git a/src/constants.py b/src/constants.py index acfe280..a41f98d 100644 --- a/src/constants.py +++ b/src/constants.py @@ -10,6 +10,7 @@ __all__ = [ "ROUND_NAMES", "TEAMS_CHANNEL_CATEGORY", "DIEGO", + "BOT", "TOURNOIS", "EMBED_COLOR", "FRACTAL_URL", @@ -30,7 +31,8 @@ if TOKEN is None: quit(1) GUILD = "690934836696973404" -DIEGO = "Diego" # Mon display name +DIEGO = 430566197868625920 # Mon id +BOT = 703305132300959754 TEAMS_CHANNEL_CATEGORY = "Channels d'équipes" EMBED_COLOR = 0xFFA500 FRACTAL_URL = "https://thefractal.space/img/{seed}.png?size=1500" @@ -65,6 +67,8 @@ class Emoji: BIN = "🗑️" DICE = "🎲" CHECK = "✅" + PLUS_1 = "👍" + MINUS_1 = "👎" class File: @@ -72,6 +76,7 @@ class File: TIRAGES = TOP_LEVEL / "data" / "tirages.yaml" TEAMS = TOP_LEVEL / "data" / "teams" JOKES = TOP_LEVEL / "data" / "jokes" + JOKES_V2 = TOP_LEVEL / "data" / "jokesv2" with open(File.TOP_LEVEL / "data" / "problems") as f: diff --git a/src/core.py b/src/core.py index 575384f..370f1c9 100644 --- a/src/core.py +++ b/src/core.py @@ -2,7 +2,7 @@ import asyncio import sys from importlib import reload -from discord import User, Message, Reaction +from discord import User, Message, Reaction, NotFound from discord.ext.commands import Bot __all__ = ["CustomBot"] @@ -67,4 +67,8 @@ class CustomBot(Bot): pass for m in msgs: - await m.clear_reaction(Emoji.BIN) + try: + await m.clear_reaction(Emoji.BIN) + except NotFound: + # Message or reaction deleted + pass