Skip to content

Commit

Permalink
feat: add anonymous messages
Browse files Browse the repository at this point in the history
Add a utils to write data to file asynchronously (for logging the anonymous messages)
  • Loading branch information
Zalk0 committed Sep 16, 2024
1 parent 1c216ab commit 757e41f
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 1 deletion.
1 change: 1 addition & 0 deletions data/discord.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ id = 1234567891234567890
channel_admin_id = 1234567891234567890
invite_link = "https://discord.gg/<replace me>"
etu_sync = true
anonymous_channels = [1234567891234567890, 1234567891234567890]

[guild.special_roles]
# id of the main roles that doesn't change
Expand Down
52 changes: 52 additions & 0 deletions etuutt_bot/commands/anon_msg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from __future__ import annotations

from datetime import datetime
from pathlib import Path
from typing import TYPE_CHECKING

from discord import Interaction, TextChannel, app_commands
from discord.ext import commands

from etuutt_bot.utils.data_write import data_write

if TYPE_CHECKING:
from etuutt_bot.bot import EtuUTTBot


class AnonMsgCog(commands.GroupCog, group_name="anon"):
"""Commandes pour envoyer des messages anonymes."""

def __init__(self, bot: EtuUTTBot):
self.bot = bot

@app_commands.command(name="send")
@app_commands.rename(channel="salon")
async def send(self, interaction: Interaction[EtuUTTBot], channel: TextChannel, message: str):
"""Envoie un message anonyme dans le salon demandé s'il le supporte."""
if channel.id not in self.bot.settings.guild.anonymous_channels:
await interaction.response.send_message(
"Le salon ne supporte pas les messages anonymes"
)
return
msg = await channel.send(f"[ANONYME] {message}")
await data_write(
f"[{datetime.now().isoformat(' ', 'seconds')}]"
f" {interaction.user.name} alias {interaction.user.display_name}"
f" a envoyé le message {msg.id} sur le salon #{channel.name}.\n",
Path("data", "logs", "anon.log"),
)
await interaction.response.send_message(
f"Votre message a bien été envoyé : {msg.jump_url}", ephemeral=True
)

@app_commands.command(name="liste")
async def list(self, interaction: Interaction[EtuUTTBot]):
"""Envoie la liste des salons dans lesquels un message anonyme peut être envoyé."""
if not self.bot.settings.guild.anonymous_channels:
await interaction.response.send_message(
"Il n'y a pas de salon configuré pour envoyer un message anonyme."
)
msg = "Les salons dans lesquels un message anonyme peut être envoyé sont :"
for c in self.bot.settings.guild.anonymous_channels:
msg += f"\n- {interaction.guild.get_channel(c).mention}"
await interaction.response.send_message(msg)
3 changes: 2 additions & 1 deletion etuutt_bot/commands_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import discord

from etuutt_bot.commands.admin import AdminCog
from etuutt_bot.commands.anon_msg import AnonMsgCog
from etuutt_bot.commands.misc import MiscCog
from etuutt_bot.commands.role import RoleCog
from etuutt_bot.commands.sync import SyncCog
Expand All @@ -23,7 +24,7 @@ async def commands_list(bot: EtuUTTBot):
await bot.add_cog(cog)

# Les cogs contenant les commandes réservées à la guilde gérée
guild_cogs: tuple = (RoleCog(bot), SyncCog(bot))
guild_cogs: tuple = (AnonMsgCog(bot), RoleCog(bot), SyncCog(bot))
for cog in guild_cogs:
await bot.add_cog(cog, guild=bot.watched_guild)

Expand Down
1 change: 1 addition & 0 deletions etuutt_bot/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class GuildConfig(BaseModel):
special_roles: SpecialRolesConfig
invite_link: Annotated[HttpUrl, UrlConstraints(default_host="discord.gg")]
etu_sync: bool
anonymous_channels: list[ChannelId]


class CategoryConfig(BaseModel):
Expand Down
25 changes: 25 additions & 0 deletions etuutt_bot/utils/data_write.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from asyncio import Lock, to_thread
from pathlib import Path

FILE_LOCKS = {}


def _get_lock(file: Path) -> Lock:
"""Retourne le verrou associé à un chemin et le crée s'il n'existe pas."""
for path, lock in FILE_LOCKS.items():
if path == file:
return lock
FILE_LOCKS.update({file: Lock()})
return FILE_LOCKS.get(file)


def _file_write(data: str, file: Path) -> None:
"""Ajoute une chaîne de caractères à la fin d'un fichier."""
with open(file, "a") as f:
f.write(data)


async def data_write(data: str, file: Path) -> None:
"""Dans un autre thread, écrit une chaîne de caractères dans un fichier."""
async with _get_lock(file):
await to_thread(_file_write, data, file)

0 comments on commit 757e41f

Please sign in to comment.