Compare commits

...

9 commits

7 changed files with 128 additions and 14 deletions

View file

@ -0,0 +1,3 @@
from . import advent, post, verein
COMMANDS = post.COMMANDS + verein.COMMANDS + advent.COMMANDS

View file

@ -0,0 +1,97 @@
import logging
from io import BytesIO
import aiohttp
import discord
from ..core.config import CONFIG
_logger = logging.getLogger(__name__)
@discord.app_commands.command(name=CONFIG.command_prefix + "advent")
async def advent(interaction: discord.Interaction, day: int | None = None) -> None:
"""
Türchen vom Lenaisten-Adventskalender öffnen (https://advent.lenaisten.de)
"""
_logger.debug(
f"User {interaction.user.name}({interaction.user.id}) used /advent (day: {day})"
)
async with aiohttp.ClientSession(
auth=aiohttp.BasicAuth(login="", password="")
) as session:
if day is None:
# Kein Tag angegeben => neuesten Tag finden
async with session.get(
"https://advent.lenaisten.de/api/user/doors"
) as http_response:
if http_response.status != 200:
# user/doors Anfrage hat nicht geklappt
await interaction.response.send_message(
content="Fehler: Ich konnte das aktuelle Türchen nicht finden :zany_face: (Probier's nochmal?)",
# nur für ausführenden User
ephemeral=True,
)
return
if not isinstance(doors := await http_response.json(), list):
# user/doors Antwort falsches Format (keine Liste)
await interaction.response.send_message(
content="Fehler: Ich konnte das aktuelle Türchen nicht finden :sweat_smile: (Probier's nochmal?)",
ephemeral=True,
)
return
days: list[int] = []
for door in doors:
if not isinstance(door, dict) or "day" not in door:
# user/doors Antwort falsches Format (Liste enthält falsche Daten)
await interaction.response.send_message(
content="Fehler: Ich konnte das aktuelle Türchen nicht finden :face_with_monocle: (Probier's nochmal?)",
ephemeral=True,
)
return
days.append(door["day"])
day = max(days)
async with session.get(
f"https://advent.lenaisten.de/api/user/image_{day}"
) as http_response:
reply_ephemeral = not CONFIG.ev_info.in_allowed_channel(interaction)
if http_response.status == 401:
# Bild (noch) nicht verfügbar
await interaction.response.send_message(
content=f"Fehler: Tag {day} kann ich (noch?) nicht abrufen. Netter Versuch! :woman_technologist_tone2:",
ephemeral=reply_ephemeral,
)
return
if http_response.status != 200:
# Bild (noch) nicht verfügbar
await interaction.response.send_message(
content="Fehler: Ich konnte das Bild nicht herunterladen :sob: (Probier's nochmal?)",
ephemeral=True,
)
return
image = discord.File(
fp=BytesIO(await http_response.read()),
filename="advent.jpg",
)
await interaction.response.send_message(
content=f"Hier ist das Bild für Tag {day}!",
file=image,
ephemeral=reply_ephemeral,
)
COMMANDS = [
advent,
]

View file

@ -4,7 +4,7 @@ from enum import Enum, auto
import discord import discord
from discord import ui from discord import ui
from .config import CONFIG from ..core.config import CONFIG
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -111,7 +111,7 @@ async def post(interaction: discord.Interaction) -> None:
f"User {interaction.user.name}({interaction.user.id}) tried to /post" f"User {interaction.user.name}({interaction.user.id}) tried to /post"
) )
await interaction.response.send_message( await interaction.response.send_message(
content="Du bist nicht berechtigt, den `/post`-Befehl zu benutzen!", content=f"Du bist nicht berechtigt, den `/{CONFIG.command_prefix}post`-Befehl zu benutzen!",
# nur für ausführenden User # nur für ausführenden User
ephemeral=True, ephemeral=True,
) )

View file

@ -3,16 +3,11 @@ import logging
import discord import discord
from .config import CONFIG, FileCommand, InfoCommand from ..core.config import CONFIG, FileCommand, InfoCommand
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
def reply_private(interaction: discord.Interaction, name: str) -> bool:
_logger.debug(f"User {interaction.user.name}({interaction.user.id}) used /{name}")
return interaction.channel_id not in CONFIG.ev_info.channels
@functools.singledispatch @functools.singledispatch
def make_command(command) -> discord.app_commands.Command: def make_command(command) -> discord.app_commands.Command:
raise NotImplementedError raise NotImplementedError
@ -25,11 +20,15 @@ def _(command: FileCommand) -> discord.app_commands.Command:
description=command.description, description=command.description,
) )
async def cmd(interaction: discord.Interaction) -> None: async def cmd(interaction: discord.Interaction) -> None:
_logger.debug(
f"User {interaction.user.name}({interaction.user.id}) used FileCommand /{command.name}"
)
if (file := await command.as_discord_file) is not None: if (file := await command.as_discord_file) is not None:
await interaction.response.send_message( await interaction.response.send_message(
content=command.content, content=command.content,
suppress_embeds=True, suppress_embeds=True,
ephemeral=reply_private(interaction, command.name), ephemeral=not CONFIG.ev_info.in_allowed_channel(interaction),
file=file, file=file,
) )
@ -49,10 +48,14 @@ def _(command: InfoCommand) -> discord.app_commands.Command:
description=command.description, description=command.description,
) )
async def cmd(interaction: discord.Interaction) -> None: async def cmd(interaction: discord.Interaction) -> None:
_logger.debug(
f"User {interaction.user.name}({interaction.user.id}) used InfoCommand /{command.name}"
)
await interaction.response.send_message( await interaction.response.send_message(
content=command.content, content=command.content,
suppress_embeds=True, suppress_embeds=True,
ephemeral=reply_private(interaction, command.name), ephemeral=not CONFIG.ev_info.in_allowed_channel(interaction),
) )
return cmd return cmd

View file

@ -2,7 +2,7 @@ import logging
import discord import discord
from . import post, verein from ..commands import COMMANDS
from .config import CONFIG from .config import CONFIG
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -16,8 +16,7 @@ class LenaverseBot(discord.Client):
) )
self.tree = discord.app_commands.CommandTree(self) self.tree = discord.app_commands.CommandTree(self)
commands = post.COMMANDS + verein.COMMANDS for command in COMMANDS:
for command in commands:
self.tree.add_command(command) self.tree.add_command(command)
async def setup_hook(self): async def setup_hook(self):

View file

@ -68,6 +68,18 @@ class ClubInfo(BaseModel):
fest: InfoCommand fest: InfoCommand
aktion: InfoCommand aktion: InfoCommand
def in_allowed_channel(self, interaction: discord.Interaction) -> bool:
if interaction.channel is None:
return False
# öffentliche Antwort erlaubt in:
# - DM channels
# - "allowed" channels
is_dm_channel = isinstance(interaction.channel, discord.DMChannel)
is_listed = interaction.channel.id in self.channels
return is_dm_channel or is_listed
class Config(BaseModel): class Config(BaseModel):
discord_token: str discord_token: str

View file

@ -3,7 +3,7 @@ authors = ["Jörn-Michael Miehe <joern-michael.miehe@lenaisten.de>"]
description = "" description = ""
name = "lenaverse_bot" name = "lenaverse_bot"
readme = "README.md" readme = "README.md"
version = "0.2.0" version = "0.3.0"
[tool.poetry.dependencies] [tool.poetry.dependencies]
aiohttp = {extras = ["speedups"], version = "^3.9.0"} aiohttp = {extras = ["speedups"], version = "^3.9.0"}