Skip to content

Commit

Permalink
Merge pull request #57 from Zalk0/dev
Browse files Browse the repository at this point in the history
Major update on Skyblock Features
  • Loading branch information
gylfirst authored Jun 24, 2024
2 parents bd4325e + d8c155e commit d49f41a
Show file tree
Hide file tree
Showing 24 changed files with 872 additions and 164 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ HYPIXEL_KEY=
HYPIXEL_GUILD_ID=
HYPIXEL_GUILD_NAME=
HYPIXEL_GUILD_ROLE=
HYPIXEL_RANK_CHANNEL=
2 changes: 1 addition & 1 deletion .github/workflows/docker-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
push: true
build-args: version=v0.0.${{ github.run_number }}
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ repos:

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.4.5
rev: v0.4.10
hooks:
# Run the linter.
- id: ruff
Expand Down
3 changes: 2 additions & 1 deletion chouette/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from chouette.bot import ChouetteBot


def main():
def main() -> None:
"""Fonction principale du bot."""
# Load the .env values if a .env file exists
if Path(".env").is_file():
load_dotenv()
Expand Down
29 changes: 17 additions & 12 deletions chouette/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
from chouette.utils.version import get_version


# Create a class of the bot
class ChouetteBot(discord.Client):
# Initialization when class is called
def __init__(self):
"""Classe principale du bot ChouetteBot."""

def __init__(self) -> None:
"""Initialise la classe ChouetteBot."""
# Associate the env variables to the bot
self.config = os.environ

Expand Down Expand Up @@ -64,7 +65,8 @@ def __init__(self):
# First declaration to be able to add commands to the guild
self.my_guild = discord.Object(int(self.config["GUILD_ID"]))

async def setup_hook(self):
async def setup_hook(self) -> None:
"""Initialise le bot."""
# Log the current running version
self.bot_logger.info(await get_version())

Expand All @@ -75,8 +77,8 @@ async def setup_hook(self):
# Start web server
await self.start_server()

# Wait until bot is ready
async def on_ready(self):
async def on_ready(self) -> None:
"""Fonction appelée lorsque le bot est prêt."""
# Waits until internal cache is ready
await self.wait_until_ready()

Expand All @@ -90,8 +92,8 @@ async def on_ready(self):
self.bot_logger.info(f"{self.user} is now online and ready!")
self.bot_logger.info(f"Number of servers I'm in : {len(self.guilds)}")

# To react to messages sent in channels bot has access to
async def on_message(self, message: discord.Message):
async def on_message(self, message: discord.Message) -> None:
"""Fonction appelée lorsqu'un message est envoyé dans les salons auxquels il a accès."""
# Ignore messages from bots including self
if message.author.bot:
return
Expand Down Expand Up @@ -119,12 +121,13 @@ async def on_message(self, message: discord.Message):
self.bot_logger.info(f'{self.user} responded to {author}: "{response[0]}"')

async def is_team_member_or_owner(self, author: discord.User) -> bool:
"""Vérifie si l'auteur est membre de l'équipe ou le propriétaire de l'application."""
if self.application.team:
return author.id in [member.id for member in self.application.team.members]
return author.id == self.application.owner.id

# Add a basic HTTP server to check if the bot is up
async def start_server(self):
async def start_server(self) -> None:
"""Démarre un serveur HTTP pour vérifier si le bot est en ligne."""
# Set a logger for the webserver
web_logger = logging.getLogger("web")
# Don't want to spam logs with site access
Expand All @@ -138,13 +141,15 @@ async def start_server(self):
}

# Remove the Server header and apply the headers
async def _default_headers(req: web.Request, res: web.StreamResponse):
async def _default_headers(req: web.Request, res: web.StreamResponse) -> None:
"""Applique les headers par défaut à la réponse."""
if "Server" in res.headers:
del res.headers["Server"]
res.headers.update(headers)

# This is the response
async def handler(req: web.Request):
async def handler(req: web.Request) -> web.Response:
"""Réponse du serveur web."""
return web.Response(text=f"{self.user.name} is up")

app = web.Application()
Expand Down
14 changes: 6 additions & 8 deletions chouette/commands/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,15 @@
from chouette.bot import ChouetteBot


# Check if user is an admin of the bot
# Maybe add server admins later
async def is_admin(interaction: discord.Interaction[ChouetteBot]):
async def is_admin(interaction: discord.Interaction[ChouetteBot]) -> bool:
"""Vérifie si l'utilisateur est un admin du bot."""
return await interaction.client.is_team_member_or_owner(interaction.user)


# Command to publish a message from admins by the bot
@app_commands.check(is_admin)
@app_commands.command(name="whisper", description="Whisper an admin message")
async def whisper(interaction: discord.Interaction[ChouetteBot], message: str):
await interaction.channel.send(
f"{interaction.client.user.name} wants to say this message: {message}"
)
@app_commands.command(name="whisper", description="Chuchotte un message")
async def whisper(interaction: discord.Interaction[ChouetteBot], message: str) -> None:
"""Chcuchotte un message par le bot, utilisable seulement pour les admins du bot."""
await interaction.channel.send(f"{interaction.client.user.name} veut dire : {message}")
await interaction.response.send_message("Commande réussie", ephemeral=True, delete_after=2)
24 changes: 13 additions & 11 deletions chouette/commands/birthdays.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@ class InvalidBirthdayDate(app_commands.AppCommandError):
pass


# Define command group based on the Group class
class Birthday(app_commands.Group):
# Set command group name and description
def __init__(self):
"""Classe qui permet de gérer les anniversaires"""

def __init__(self) -> None:
"""Initialise la classe Birthday"""
super().__init__(name="birthday", description="Commandes pour gérer les anniversaires")

async def on_error(
self, interaction: Interaction[ChouetteBot], error: app_commands.AppCommandError
) -> None:
"""Gère les erreurs lors de l'exécution des commandes."""
if isinstance(error, InvalidBirthdayDate):
interaction.client.bot_logger.info(
f"{interaction.user} entered an invalid date as his birthday"
Expand All @@ -38,15 +40,15 @@ async def on_error(
"Vous n'avez pas entré une date d'anniversaire valide", ephemeral=True
)

# Make a command to add a birthday
@app_commands.command(
name="add",
description="Permet d'enregistrer son anniversaire",
)
@app_commands.describe(day="Nombre entier", month="Nombre entier", year="Nombre entier")
async def add(
self, interaction: Interaction[ChouetteBot], day: int, month: int, year: int | None
):
) -> None:
"""Ajoute l'anniversaire de l'utilisateur dans la base de données."""
try:
birth_date = await check_date(day, month, year)
except ValueError as e:
Expand All @@ -68,15 +70,15 @@ async def add(
ephemeral=True,
)

# Make a command to modify the birthday
@app_commands.command(
name="modify",
description="Permet de modifier son anniversaire enregistré",
)
@app_commands.describe(day="Nombre entier", month="Nombre entier", year="Nombre entier")
async def modify(
self, interaction: Interaction[ChouetteBot], day: int, month: int, year: int | None
):
) -> None:
"""Modifie l'anniversaire de l'utilisateur dans la base de données."""
try:
birth_date = await check_date(day, month, year)
except ValueError as e:
Expand All @@ -97,12 +99,12 @@ async def modify(
ephemeral=True,
)

# Make a command to remove the birthday
@app_commands.command(
name="remove",
description="Permet de supprimer son anniversaire enregistré",
)
async def remove(self, interaction: Interaction[ChouetteBot]):
async def remove(self, interaction: Interaction[ChouetteBot]) -> None:
"""Supprimer l'anniversaire de l'utilisateur de la base de données."""
user_id = str(interaction.user.id)
birthdays = await load_birthdays()
if user_id in birthdays:
Expand All @@ -116,12 +118,12 @@ async def remove(self, interaction: Interaction[ChouetteBot]):
ephemeral=True,
)

# Make a command to list all birthdays listed in database, sorted by date
@app_commands.command(
name="list",
description="Liste les anniversaires enregistrés",
)
async def list(self, interaction: Interaction[ChouetteBot]):
async def list(self, interaction: Interaction[ChouetteBot]) -> None:
"""Liste les anniversaires enregistrés dans la base de données triés par date."""
msg = f"Voici les anniversaires de {interaction.guild.name}\n"
birthdays = sorted(
(await load_birthdays()).items(), key=lambda x: x[1].get("birthday").replace(4)
Expand Down
70 changes: 40 additions & 30 deletions chouette/commands/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,34 @@
from chouette.bot import ChouetteBot


# Make a LaTeX command
@app_commands.command(name="latex", description="Render a LaTeX equation")
async def latex(interaction: discord.Interaction[ChouetteBot], equation: str):
@app_commands.command(name="latex", description="Fait le rendu d'une équation LaTeX")
async def latex(interaction: discord.Interaction[ChouetteBot], equation: str) -> None:
"""Fait le rendu d'une équation LaTeX et envoie la réponse sous forme d'image."""
await interaction.response.send_message(file=await latex_render(equation))


# Make the roll command
@app_commands.command(name="roll", description="Roll a die")
async def die_roll(interaction: discord.Interaction[ChouetteBot]):
@app_commands.command(name="roll", description="Lance un dé")
async def die_roll(interaction: discord.Interaction[ChouetteBot]) -> None:
"""Lance un dé et affiche le résultat."""
await interaction.response.send_message(f"{random.randint(1, 6)} \N{GAME DIE}")


# Make the ping command
@app_commands.command(name="ping", description="Test the ping of the bot")
async def ping(interaction: discord.Interaction[ChouetteBot]):
@app_commands.command(name="ping", description="Test la latence du bot")
async def ping(interaction: discord.Interaction[ChouetteBot]) -> None:
"""Test la latence du bot."""
await interaction.response.send_message(
f"Pong! In {round(interaction.client.latency * 1000)}ms"
f"Pong ! En {round(interaction.client.latency * 1000)}ms"
)


# Make a cheh command
@app_commands.command(name="cheh", description="Cheh somebody")
async def cheh(interaction: discord.Interaction[ChouetteBot], user: discord.Member):
# Check if the user to cheh is the bot or the user sending the command
@app_commands.command(name="cheh", description="Cheh quelqu'un")
async def cheh(interaction: discord.Interaction[ChouetteBot], user: discord.Member) -> None:
"""
Envoie le gif du Cheh à quelqu'un.
On vérifie l'utilisateur qui a été mentionné, si c'est le bot, on envoie un message d'erreur.
Si c'est l'utilisateur qui a fait la commande, on envoie **FEUR**.
"""
if user == interaction.client.user:
await interaction.response.send_message("Vous ne pouvez pas me **Cheh** !")
elif user == interaction.user:
Expand All @@ -47,49 +51,55 @@ async def cheh(interaction: discord.Interaction[ChouetteBot], user: discord.Memb
await interaction.channel.send(cheh_gif)


# Make a simple context menu application to pin/unpin
@app_commands.guild_only
@app_commands.checks.bot_has_permissions(manage_messages=True)
@app_commands.context_menu(name="Pin/Unpin")
async def pin(interaction: discord.Interaction[ChouetteBot], message: discord.Message):
@app_commands.context_menu(name="Epingler/Déséingler")
async def pin(interaction: discord.Interaction[ChouetteBot], message: discord.Message) -> None:
"""Épingle ou désépingle un message."""
if message.pinned:
await message.unpin()
await interaction.response.send_message("The message has been unpinned!", ephemeral=True)
await interaction.response.send_message("Le message a été désépinglé !", ephemeral=True)
else:
await message.pin()
await interaction.response.send_message("The message has been pinned!", ephemeral=True)
await interaction.response.send_message("Le message a été épinglé !", ephemeral=True)


# Make a context menu command to delete messages
@app_commands.guild_only
@app_commands.default_permissions(manage_messages=True)
@app_commands.checks.bot_has_permissions(
manage_messages=True, read_message_history=True, read_messages=True
)
@app_commands.checks.has_permissions(manage_messages=True)
@app_commands.context_menu(name="Delete until here")
async def delete(interaction: discord.Interaction[ChouetteBot], message: discord.Message):
@app_commands.context_menu(name="Supprime jusqu'ici")
async def delete(interaction: discord.Interaction[ChouetteBot], message: discord.Message) -> None:
"""Supprime les messages jusqu'à celui-ci (inclus)."""
await interaction.response.defer(ephemeral=True, thinking=True)
last_id = interaction.channel.last_message_id

def is_msg(msg: discord.Message) -> bool:
"""
Vérifie si le message est dans l'intervalle (dernier message ↔ message sélectionné).
On décale les IDs de 22 bits pour obtenir le timestamp du message.
"""
return (message.id >> 22) <= (msg.id >> 22) <= (last_id >> 22)

del_msg = await message.channel.purge(bulk=True, reason="Admin used bulk delete", check=is_msg)
await interaction.followup.send(f"{len(del_msg)} messages supprimés !")


# Make a bot information command
@app_commands.command(name="info", description="Display bot infos")
async def info(interaction: discord.Interaction[ChouetteBot]):
@app_commands.command(name="info", description="Affiche les informations du bot")
async def info(interaction: discord.Interaction[ChouetteBot]) -> None:
"""Affiche les informations du bot."""
creators = "Zalko & Gylfirst"
last_update = await get_last_update()
github_link = "https://github.com/Zalk0/ChouetteBot-discord"
dockerhub_link = "https://hub.docker.com/r/gylfirst/chouettebot"
await interaction.response.send_message(
f"Discord Bot created by: {creators}\n\n"
f"Project developed in our free time. You can ask for features on GitHub.\n"
f"[Source code](<{github_link}>)\n"
f"[Docker image](<{dockerhub_link}>)\n\n"
f"Last update: {last_update}"
f"Bot Discord créé par : {creators}\n\n"
"Projet développé pendant notre temps libre. "
"Vous pouvez demander des fonctionnalités sur GitHub.\n"
f"[Code source](<{github_link}>)\n"
f"[Image Docker](<{dockerhub_link}>)\n\n"
f"Dernière mise à jour : {last_update}"
)
Loading

0 comments on commit d49f41a

Please sign in to comment.