Skip to content

Commit a7961ea

Browse files
authored
Merge branch 'main' into dependabot/github_actions/astral-sh/setup-uv-7
2 parents c5221ff + 39d78ab commit a7961ea

13 files changed

Lines changed: 334 additions & 117 deletions

File tree

.github/workflows/build-deploy.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ jobs:
1717

1818
# Check out the current repository in the `sir-lancebot` subdirectory
1919
- name: Checkout code
20-
uses: actions/checkout@v4
20+
uses: actions/checkout@v6
2121

2222
- name: Set up Docker Buildx
23-
uses: docker/setup-buildx-action@v3
23+
uses: docker/setup-buildx-action@v4
2424

2525
- name: Login to Github Container Registry
26-
uses: docker/login-action@v3
26+
uses: docker/login-action@v4
2727
with:
2828
registry: ghcr.io
2929
username: ${{ github.repository_owner }}
@@ -54,7 +54,7 @@ jobs:
5454

5555
steps:
5656
- name: Checkout Kubernetes Repository
57-
uses: actions/checkout@v4
57+
uses: actions/checkout@v6
5858
with:
5959
repository: python-discord/infra
6060
path: infra

.github/workflows/lint.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99

1010
steps:
1111
- name: Checkout repository
12-
uses: actions/checkout@v4
12+
uses: actions/checkout@v6
1313

1414
- name: Install uv
1515
uses: astral-sh/setup-uv@v7

.github/workflows/sentry_release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
runs-on: ubuntu-latest
88
steps:
99
- name: Checkout code
10-
uses: actions/checkout@v4
10+
uses: actions/checkout@v6
1111

1212
- name: Create a Sentry.io release
1313
uses: getsentry/action-release@v3

bot/exts/core/help.py

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from contextlib import suppress
55
from typing import NamedTuple
66

7-
from discord import Colour, Embed, HTTPException, Message, Reaction, User
7+
from discord import ChannelType, Colour, Embed, HTTPException, Message, NotFound, Object, RawReactionActionEvent
88
from discord.ext import commands
99
from discord.ext.commands import CheckFailure, Cog as DiscordCog, Command, Context
1010
from pydis_core.utils.logging import get_logger
@@ -182,33 +182,43 @@ def reset_timeout(self) -> None:
182182
# recreate the timeout task
183183
self._timeout_task = self._bot.loop.create_task(self.timeout())
184184

185-
async def on_reaction_add(self, reaction: Reaction, user: User) -> None:
186-
"""Event handler for when reactions are added on the help message."""
187-
# ensure it was the relevant session message
188-
if reaction.message.id != self.message.id:
185+
186+
async def on_raw_reaction_add(self, payload: RawReactionActionEvent) -> None:
187+
"""Handle raw reaction events for DM compatibility."""
188+
# Ignore if not our message
189+
if payload.message_id != self.message.id:
189190
return
190191

191-
# ensure it was the session author who reacted
192-
if user.id != self.author.id:
192+
# Ignore if not the session author
193+
if payload.user_id != self.author.id:
193194
return
194195

195-
emoji = str(reaction.emoji)
196+
# Get the emoji string
197+
emoji = str(payload.emoji)
196198

197-
# check if valid action
199+
# Check if valid action
198200
if emoji not in REACTIONS:
199201
return
200202

201203
self.reset_timeout()
202204

205+
# Remove the reaction to prep for re-use
206+
try:
207+
# We need to get the actual message and user objects for remove_reaction
208+
channel = self._bot.get_channel(payload.channel_id)
209+
if channel and channel.type != ChannelType.private:
210+
# channel is None in DMs, this condition skips reaction removal in DMs to prevent exceptions
211+
message = channel.get_partial_message(payload.message_id)
212+
await message.remove_reaction(payload.emoji, Object(id=payload.user_id))
213+
except (HTTPException, NotFound):
214+
# Ignore errors when removing reactions
215+
pass
216+
203217
# Run relevant action method
204218
action = getattr(self, f"do_{REACTIONS[emoji]}", None)
205219
if action:
206220
await action()
207221

208-
# remove the added reaction to prep for re-use
209-
with suppress(HTTPException):
210-
await self.message.remove_reaction(reaction, user)
211-
212222
async def on_message_delete(self, message: Message) -> None:
213223
"""Closes the help session when the help message is deleted."""
214224
if message.id == self.message.id:
@@ -219,7 +229,7 @@ async def prepare(self) -> None:
219229
await self.build_pages()
220230
await self.update_page()
221231

222-
self._bot.add_listener(self.on_reaction_add)
232+
self._bot.add_listener(self.on_raw_reaction_add)
223233
self._bot.add_listener(self.on_message_delete)
224234

225235
self.add_reactions()
@@ -459,7 +469,7 @@ async def start(cls, ctx: Context, *command, **options) -> "HelpSession":
459469

460470
async def stop(self) -> None:
461471
"""Stops the help session, removes event listeners and attempts to delete the help message."""
462-
self._bot.remove_listener(self.on_reaction_add)
472+
self._bot.remove_listener(self.on_raw_reaction_add)
463473
self._bot.remove_listener(self.on_message_delete)
464474

465475
# ignore if permission issue, or the message doesn't exist

bot/exts/fun/fun.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import Literal
66

77
import pyjokes
8+
from aiohttp import ClientError, ClientResponseError
89
from discord import Embed
910
from discord.ext import commands
1011
from discord.ext.commands import BadArgument, Cog, Context
@@ -14,6 +15,7 @@
1415
from bot.bot import Bot
1516
from bot.constants import Client, Colours, Emojis
1617
from bot.utils import helpers, messages
18+
from bot.utils.quote import daily_quote, random_quote
1719

1820
log = get_logger(__name__)
1921

@@ -158,6 +160,57 @@ async def joke(self, ctx: commands.Context, category: Literal["neutral", "chuck"
158160
joke = pyjokes.get_joke(category=category)
159161
await ctx.send(joke)
160162

163+
@commands.group(name="quote")
164+
async def quote(self, ctx: Context) -> None:
165+
"""
166+
Retrieve a quote from zenquotes.io api.
167+
168+
See `random`, `daily` subcommands.
169+
"""
170+
if ctx.invoked_subcommand is None:
171+
await ctx.invoke(self.bot.get_command("help"), "quote")
172+
173+
@quote.command(name="daily")
174+
async def quote_daily(self, ctx: Context) -> None:
175+
"""Retrieve the daily quote from zenquotes.io api."""
176+
try:
177+
quote = await daily_quote(self.bot)
178+
embed = Embed(
179+
title="Daily Quote",
180+
description=f"> {quote}\n\n-# Powered by [zenquotes.io](https://zenquotes.io)",
181+
colour=Colours.blue
182+
)
183+
await ctx.send(embed=embed)
184+
except ClientResponseError as e:
185+
log.warning(f"ZenQuotes API error: {e.status} {e.message}")
186+
await ctx.send(":x: Could not retrieve quote from API.")
187+
except (ClientError, TimeoutError) as e:
188+
log.error(f"Network error fetching quote: {e}")
189+
await ctx.send(":x: Could not connect to the quote service.")
190+
except Exception:
191+
log.exception("Unexpected error fetching quote.")
192+
await ctx.send(":x: Something unexpected happened. Try again later.")
193+
194+
@quote.command(name="random")
195+
async def quote_random(self, ctx: Context) -> None:
196+
"""Retrieve a random quote from zenquotes.io api."""
197+
try:
198+
quote = await random_quote(self.bot)
199+
embed = Embed(
200+
title="Random Quote",
201+
description=f"> {quote}\n\n-# Powered by [zenquotes.io](https://zenquotes.io)",
202+
colour=Colours.blue
203+
)
204+
await ctx.send(embed=embed)
205+
except ClientResponseError as e:
206+
log.warning(f"ZenQuotes API error: {e.status} {e.message}")
207+
await ctx.send(":x: Could not retrieve quote from API.")
208+
except (ClientError, TimeoutError) as e:
209+
log.error(f"Network error fetching quote: {e}")
210+
await ctx.send(":x: Could not connect to the quote service.")
211+
except Exception:
212+
log.exception("Unexpected error fetching quote.")
213+
await ctx.send(":x: Something unexpected happened. Try again later.")
161214

162215
async def setup(bot: Bot) -> None:
163216
"""Load the Fun cog."""

bot/exts/fun/space.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# XXX: Disabled due to issues with NASA API, see https://github.com/python-discord/sir-lancebot/issues/1709
2+
13
import random
24
from datetime import UTC, date, datetime
35
from typing import Any
@@ -231,4 +233,7 @@ async def setup(bot: Bot) -> None:
231233
logger.warning("Can't find NASA API key. Not loading Space Cog.")
232234
return
233235

234-
await bot.add_cog(Space(bot))
236+
# XXX: Disabled due to issues with NASA API, see https://github.com/python-discord/sir-lancebot/issues/1709
237+
238+
# await bot.add_cog(Space(bot))
239+
return

bot/exts/fun/status_codes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ def __init__(self, bot: Bot):
2727
self.bot = bot
2828

2929
@commands.group(
30-
name="http_status",
31-
aliases=("status", "httpstatus"),
30+
name="http",
31+
aliases=("http_status", "httpstatus", "status"),
3232
invoke_without_command=True,
3333
)
3434
async def http_status_group(self, ctx: commands.Context, code: int) -> None:

bot/exts/holidays/holidayreact.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class Holiday(NamedTuple):
7575
"jack-o-lantern": Trigger(r"\bjack-o-lantern\b", ["\U0001F383"]),
7676
"pumpkin": Trigger(r"\bpumpkin\b", ["\U0001F383"]),
7777
"skeleton": Trigger(r"\bskeleton\b", ["\U0001F480"]),
78-
"spooky": Trigger(r"\bspo{2,}[k|p][i|y](er|est)?\b", ["\U0001F47B"]),
78+
"spooky": Trigger(r"\bspo{2,}[kp][iy](er|est)?\b", ["\U0001F47B"]),
7979
}
8080
)
8181
Hanukkah = Holiday([Month.NOVEMBER, Month.DECEMBER], {

0 commit comments

Comments
 (0)