Skip to content

feat:(bookmarks) added removing bookmarks #904

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 22 commits into from
Closed
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b9c797a
wip changes
cherryl1k Jun 9, 2025
89691c3
Merge branch 'main' of https://github.com/cherryl1k/tux
cherryl1k Jun 9, 2025
38c22a5
Merge branch 'allthingslinux:main' into main
cherryl1k Jun 19, 2025
56bebaf
Added removing bookmarks from the bot's DMs
cherryl1k Jun 19, 2025
217c364
fix(bookmarks): improve emoji validation and error handling for user …
electron271 Jun 19, 2025
b8a4072
added eletrons changes and fixed a warning
cherryl1k Jun 19, 2025
f16d0f9
Merge branch 'main' of https://github.com/cherryl1k/tux
cherryl1k Jun 19, 2025
34798e9
i think i fixed whatever the hell git just did
cherryl1k Jun 19, 2025
e9119ab
Merge branch 'allthingslinux:main' into main
cherryl1k Jun 19, 2025
72d3054
Merge branch 'allthingslinux:main' into main
cherryl1k Jun 19, 2025
b547dd4
Merge branch 'main' of https://github.com/cherryl1k/tux
cherryl1k Jun 20, 2025
0b4d6d9
Merge branch 'allthingslinux:main' into main
cherryl1k Jun 20, 2025
ba2c381
chore(wip): still working on debugging
cherryl1k Jun 20, 2025
1c5f20e
wip changes
cherryl1k Jun 9, 2025
bdb6103
Added removing bookmarks from the bot's DMs
cherryl1k Jun 19, 2025
66f4df9
added eletrons changes and fixed a warning
cherryl1k Jun 19, 2025
b5dcbb7
fix(bookmarks): improve emoji validation and error handling for user …
electron271 Jun 19, 2025
2ce131a
chore(wip): still working on debugging
cherryl1k Jun 20, 2025
5d36f15
Merge branch 'main' of https://github.com/cherryl1k/tux
cherryl1k Jun 20, 2025
e0148cd
Merge branch 'main' of https://github.com/allthingslinux/tux
cherryl1k Jun 21, 2025
61d1a22
feat:(bookmarks) cleaned up removing bookmarks
cherryl1k Jun 21, 2025
67b53e2
Merge branch 'main' into main
kzndotsh Jun 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 46 additions & 16 deletions tux/cogs/services/bookmarks.py
Original file line number Diff line number Diff line change
@@ -13,6 +13,16 @@ class Bookmarks(commands.Cog):
def __init__(self, bot: Tux) -> None:
self.bot = bot

self.valid_add_emojis = CONST.ADD_BOOKMARK
self.valid_remove_emojis = CONST.REMOVE_BOOKMARK
self.valid_emojis = CONST.ADD_BOOKMARK + CONST.REMOVE_BOOKMARK

# The linter wants to change this but it breaks when it does that
def _is_valid_emoji(self, emoji: discord.PartialEmoji, valid_list: str) -> bool:
if emoji.name in valid_list: # noqa: SIM103
return True
return False

@commands.Cog.listener()
async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) -> None:
"""
@@ -27,15 +37,30 @@ async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) ->
-------
None
"""

if str(payload.emoji) != "🔖":
if not self._is_valid_emoji(payload.emoji, self.valid_emojis):
return

# Get the user who reacted to the message
user = self.bot.get_user(payload.user_id)
if user is None:
try:
user = await self.bot.fetch_user(payload.user_id)
except discord.NotFound:
logger.error(f"User not found for ID: {payload.user_id}")
except (discord.Forbidden, discord.HTTPException) as fetch_error:
logger.error(f"Failed to fetch user: {fetch_error}")
return
# Fetch the channel where the reaction was added
channel = self.bot.get_channel(payload.channel_id)
if channel is None:
logger.error(f"Channel not found for ID: {payload.channel_id}")
try:
channel = await self.bot.fetch_channel(payload.channel_id)
except discord.NotFound:
logger.error(f"Channel not found for ID: {payload.channel_id}")
except (discord.Forbidden, discord.HTTPException) as fetch_error:
logger.error(f"Failed to fetch channel: {fetch_error}")
return

channel = cast(discord.TextChannel | discord.Thread, channel)

# Fetch the message that was reacted to
@@ -48,19 +73,20 @@ async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) ->
logger.error(f"Failed to fetch message: {fetch_error}")
return

# Create an embed for the bookmarked message
embed = self._create_bookmark_embed(message)
# check for what to do
if self._is_valid_emoji(payload.emoji, self.valid_add_emojis):
# Create an embed for the bookmarked message
embed = await self._create_bookmark_embed(message)

# Get the user who reacted to the message
user = self.bot.get_user(payload.user_id)
if user is None:
logger.error(f"User not found for ID: {payload.user_id}")
return
# Send the bookmarked message to the user
await self._send_bookmark(user, message, embed, payload.emoji)

# Send the bookmarked message to the user
await self._send_bookmark(user, message, embed, payload.emoji)
elif self._is_valid_emoji(payload.emoji, self.valid_remove_emojis) and user is not self.bot.user:
await self._delete_bookmark(message, user)
else:
return

def _create_bookmark_embed(
async def _create_bookmark_embed(
self,
message: discord.Message,
) -> discord.Embed:
@@ -77,13 +103,16 @@ def _create_bookmark_embed(
embed.add_field(name="Author", value=message.author.name, inline=False)

embed.add_field(name="Jump to Message", value=f"[Click Here]({message.jump_url})", inline=False)

if message.attachments:
attachments_info = "\n".join([attachment.url for attachment in message.attachments])
embed.add_field(name="Attachments", value=attachments_info, inline=False)

return embed

async def _delete_bookmark(self, message: discord.Message, user: discord.User) -> None:
if message.author is not self.bot.user:
return
Comment on lines +112 to +113
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Using 'is not' for author comparison may not be reliable.

Object identity isn't guaranteed; compare author IDs instead for accuracy.

Suggested change
if message.author is not self.bot.user:
return
if message.author.id != self.bot.user.id:
return

await message.delete()

@staticmethod
async def _send_bookmark(
user: discord.User,
@@ -107,7 +136,8 @@ async def _send_bookmark(
"""

try:
await user.send(embed=embed)
dm_message = await user.send(embed=embed)
await dm_message.add_reaction(CONST.REMOVE_BOOKMARK)
Comment on lines +139 to +140
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Adding a reaction to the DM message may fail if the bot lacks permissions.

Handle or document the potential exception if adding a reaction to a DM fails due to permission issues.


except (discord.Forbidden, discord.HTTPException) as dm_error:
logger.error(f"Cannot send a DM to {user.name}: {dm_error}")
18 changes: 11 additions & 7 deletions tux/cogs/utility/poll.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import cast

import discord
from discord import app_commands
from discord.ext import commands
@@ -74,13 +76,15 @@ async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) ->
# get reaction from payload.message_id, payload.channel_id, payload.guild_id, payload.emoji
channel = self.bot.get_channel(payload.channel_id)
if channel is None:
logger.error(f"Channel with ID {payload.channel_id} not found.")
return
if isinstance(channel, discord.ForumChannel | discord.CategoryChannel | discord.abc.PrivateChannel):
logger.error(
f"Channel with ID {payload.channel_id} is not a compatible channel type. How the fuck did you get here?",
)
return
try:
channel = await self.bot.fetch_channel(payload.channel_id)
except discord.NotFound:
logger.error(f"Channel not found for ID: {payload.channel_id}")
return
except (discord.Forbidden, discord.HTTPException) as fetch_error:
logger.error(f"Failed to fetch channel: {fetch_error}")
return
channel = cast(discord.TextChannel | discord.Thread, channel)

message = await channel.fetch_message(payload.message_id)
# Lookup the reaction object for this event
4 changes: 4 additions & 0 deletions tux/utils/constants.py
Original file line number Diff line number Diff line change
@@ -73,5 +73,9 @@ class Constants:
EIGHT_BALL_QUESTION_LENGTH_LIMIT = 120
EIGHT_BALL_RESPONSE_WRAP_WIDTH = 30

# Bookmark constants
ADD_BOOKMARK = "🔖"
REMOVE_BOOKMARK = "🗑️"


CONST = Constants()