Compare commits
4 Commits
1cf10fc7a9
...
kewlrewrit
Author | SHA1 | Date | |
---|---|---|---|
480b36ad85 | |||
679fedb099 | |||
12f705418a | |||
865cd9ba6d |
13
Dockerfile
13
Dockerfile
@ -1,13 +1,22 @@
|
|||||||
FROM python:3.13-slim
|
# syntax=docker/dockerfile:1
|
||||||
|
# check=error=true;experimental=all
|
||||||
|
|
||||||
|
FROM python:3.13-slim@sha256:6544e0e002b40ae0f59bc3618b07c1e48064c4faed3a15ae2fbd2e8f663e8283
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
|
|
||||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
||||||
|
|
||||||
RUN useradd -m botuser && mkdir -p /home/botuser/data
|
RUN useradd -m botuser && mkdir -p /home/botuser/data
|
||||||
WORKDIR /home/botuser
|
WORKDIR /home/botuser
|
||||||
|
|
||||||
COPY interactions /home/botuser/interactions
|
COPY interactions /home/botuser/interactions
|
||||||
COPY discord_reminder_bot /home/botuser/discord_reminder_bot
|
COPY discord_reminder_bot /home/botuser/discord_reminder_bot
|
||||||
|
|
||||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||||
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
|
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
|
||||||
uv sync --no-install-project
|
uv sync --no-install-project
|
||||||
|
|
||||||
VOLUME ["/home/botuser/data/"]
|
VOLUME ["/home/botuser/data/"]
|
||||||
CMD ["uv", "run", "discord_reminder_bot/main.py"]
|
CMD ["uv", "run", "python", "-m", "discord_reminder_bot.main"]
|
||||||
|
@ -52,7 +52,7 @@ sentry_sdk.init(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def generate_markdown_state(state: dict[str, Any]) -> str:
|
def generate_state(state: dict[str, Any]) -> str:
|
||||||
"""Format the __getstate__ dictionary for Discord markdown.
|
"""Format the __getstate__ dictionary for Discord markdown.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -62,7 +62,7 @@ def generate_markdown_state(state: dict[str, Any]) -> str:
|
|||||||
str: The formatted string.
|
str: The formatted string.
|
||||||
"""
|
"""
|
||||||
if not state:
|
if not state:
|
||||||
return "```json\nNo state found.\n```"
|
return "No state found.\n"
|
||||||
|
|
||||||
# discord.app_commands.errors.CommandInvokeError: Command 'remove' raised an exception: TypeError: Object of type IntervalTrigger is not JSON serializable
|
# discord.app_commands.errors.CommandInvokeError: Command 'remove' raised an exception: TypeError: Object of type IntervalTrigger is not JSON serializable
|
||||||
|
|
||||||
@ -83,8 +83,21 @@ def generate_markdown_state(state: dict[str, Any]) -> str:
|
|||||||
e.add_note("This is likely due to a non-serializable object in the state. Please check the state for any non-serializable objects.")
|
e.add_note("This is likely due to a non-serializable object in the state. Please check the state for any non-serializable objects.")
|
||||||
e.add_note(f"{state=}")
|
e.add_note(f"{state=}")
|
||||||
logger.error(f"Failed to serialize state: {e}")
|
logger.error(f"Failed to serialize state: {e}")
|
||||||
return "```json\nFailed to serialize state.\n```"
|
return "Failed to serialize state."
|
||||||
|
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def generate_markdown_state(state: dict[str, Any]) -> str:
|
||||||
|
"""Format the __getstate__ dictionary for Discord markdown.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
state (dict): The __getstate__ dictionary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The formatted string.
|
||||||
|
"""
|
||||||
|
msg: str = generate_state(state)
|
||||||
return "```json\n" + msg + "\n```"
|
return "```json\n" + msg + "\n```"
|
||||||
|
|
||||||
|
|
||||||
@ -206,6 +219,8 @@ def get_scheduler() -> AsyncIOScheduler:
|
|||||||
msg: str = f"Invalid timezone: {config_timezone}. Error: {e}"
|
msg: str = f"Invalid timezone: {config_timezone}. Error: {e}"
|
||||||
raise ValueError(msg) from e
|
raise ValueError(msg) from e
|
||||||
|
|
||||||
|
logger.info(f"Using timezone: {config_timezone}. If this is incorrect, please set the TIMEZONE environment variable.")
|
||||||
|
|
||||||
sqlite_location: str = os.getenv("SQLITE_LOCATION", default="/jobs.sqlite")
|
sqlite_location: str = os.getenv("SQLITE_LOCATION", default="/jobs.sqlite")
|
||||||
logger.info(f"Using SQLite database at: {sqlite_location}")
|
logger.info(f"Using SQLite database at: {sqlite_location}")
|
||||||
|
|
||||||
@ -304,17 +319,25 @@ def format_job_for_ui(job: Job) -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
str: The formatted string.
|
str: The formatted string.
|
||||||
"""
|
"""
|
||||||
msg: str = f"**{job.kwargs.get('message', '')}**\n"
|
msg: str = f"\nMessage: {job.kwargs.get('message', '')}\n"
|
||||||
msg += f"ID: {job.id}\n"
|
msg += f"ID: {job.id}\n"
|
||||||
msg += f"Trigger: {job.trigger} {get_human_readable_time(job)}\n"
|
msg += f"Trigger: {job.trigger} {get_human_readable_time(job)}\n"
|
||||||
|
|
||||||
if job.kwargs.get("user_id"):
|
if job.kwargs.get("user_id"):
|
||||||
msg += f"User: <@{job.kwargs.get('user_id')}>\n"
|
msg += f"User: <@{job.kwargs.get('user_id')}>\n"
|
||||||
|
if job.kwargs.get("guild_id"):
|
||||||
|
guild_id: int = job.kwargs.get("guild_id")
|
||||||
|
msg += f"Guild: {guild_id}\n"
|
||||||
|
if job.kwargs.get("author_id"):
|
||||||
|
author_id: int = job.kwargs.get("author_id")
|
||||||
|
msg += f"Author: <@{author_id}>\n"
|
||||||
if job.kwargs.get("channel_id"):
|
if job.kwargs.get("channel_id"):
|
||||||
channel = bot.get_channel(job.kwargs.get("channel_id"))
|
channel = bot.get_channel(job.kwargs.get("channel_id"))
|
||||||
if channel and isinstance(channel, discord.abc.GuildChannel | discord.Thread):
|
if channel and isinstance(channel, discord.abc.GuildChannel | discord.Thread):
|
||||||
msg += f"Channel: #{channel.name}\n"
|
msg += f"Channel: #{channel.name}\n"
|
||||||
|
|
||||||
|
msg += f"\nData:\n{generate_state(job.__getstate__())}\n"
|
||||||
|
|
||||||
logger.debug(f"Formatted job for UI: {msg}")
|
logger.debug(f"Formatted job for UI: {msg}")
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
@ -400,8 +423,7 @@ class ReminderListView(discord.ui.View):
|
|||||||
return "No reminders found on this page."
|
return "No reminders found on this page."
|
||||||
|
|
||||||
job: Job = jobs[0]
|
job: Job = jobs[0]
|
||||||
idx: int = start + 1
|
return f"```{format_job_for_ui(job)}```"
|
||||||
return f"**Your Reminder:**\n```{idx}. {format_job_for_ui(job)}```"
|
|
||||||
|
|
||||||
async def refresh(self, interaction: discord.Interaction) -> None:
|
async def refresh(self, interaction: discord.Interaction) -> None:
|
||||||
"""Refresh the view and update the message with the current page content.
|
"""Refresh the view and update the message with the current page content.
|
||||||
@ -417,21 +439,25 @@ class ReminderListView(discord.ui.View):
|
|||||||
|
|
||||||
async def goto_first_page(self, interaction: discord.Interaction) -> None:
|
async def goto_first_page(self, interaction: discord.Interaction) -> None:
|
||||||
"""Go to the first page of reminders."""
|
"""Go to the first page of reminders."""
|
||||||
|
await interaction.response.defer()
|
||||||
self.current_page = 0
|
self.current_page = 0
|
||||||
await self.refresh(interaction)
|
await self.refresh(interaction)
|
||||||
|
|
||||||
async def goto_prev_page(self, interaction: discord.Interaction) -> None:
|
async def goto_prev_page(self, interaction: discord.Interaction) -> None:
|
||||||
"""Go to the previous page of reminders."""
|
"""Go to the previous page of reminders."""
|
||||||
|
await interaction.response.defer()
|
||||||
self.current_page -= 1
|
self.current_page -= 1
|
||||||
await self.refresh(interaction)
|
await self.refresh(interaction)
|
||||||
|
|
||||||
async def goto_next_page(self, interaction: discord.Interaction) -> None:
|
async def goto_next_page(self, interaction: discord.Interaction) -> None:
|
||||||
"""Go to the next page of reminders."""
|
"""Go to the next page of reminders."""
|
||||||
|
await interaction.response.defer()
|
||||||
self.current_page += 1
|
self.current_page += 1
|
||||||
await self.refresh(interaction)
|
await self.refresh(interaction)
|
||||||
|
|
||||||
async def goto_last_page(self, interaction: discord.Interaction) -> None:
|
async def goto_last_page(self, interaction: discord.Interaction) -> None:
|
||||||
"""Go to the last page of reminders."""
|
"""Go to the last page of reminders."""
|
||||||
|
await interaction.response.defer()
|
||||||
self.current_page = self.total_pages - 1
|
self.current_page = self.total_pages - 1
|
||||||
await self.refresh(interaction)
|
await self.refresh(interaction)
|
||||||
|
|
||||||
@ -524,6 +550,7 @@ class ReminderListView(discord.ui.View):
|
|||||||
bool: True if the interaction is valid, False otherwise.
|
bool: True if the interaction is valid, False otherwise.
|
||||||
"""
|
"""
|
||||||
if interaction.user != self.interaction.user:
|
if interaction.user != self.interaction.user:
|
||||||
|
logger.debug(f"Interaction user {interaction.user} is not the same as the view's interaction user {self.interaction.user}.")
|
||||||
await interaction.response.send_message("This is not your reminder list!", ephemeral=True)
|
await interaction.response.send_message("This is not your reminder list!", ephemeral=True)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
Reference in New Issue
Block a user