aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/exts/utilities/bookmark.py206
1 files changed, 53 insertions, 153 deletions
diff --git a/bot/exts/utilities/bookmark.py b/bot/exts/utilities/bookmark.py
index 511a3eff..65a32203 100644
--- a/bot/exts/utilities/bookmark.py
+++ b/bot/exts/utilities/bookmark.py
@@ -1,34 +1,19 @@
import logging
import random
-from typing import Callable, Optional
+from typing import Optional
import discord
from discord.ext import commands
from bot.bot import Bot
from bot.constants import Colours, ERROR_REPLIES, Icons, Roles
-from bot.utils.converters import WrappedMessageConverter
from bot.utils.decorators import whitelist_override
log = logging.getLogger(__name__)
-# Number of seconds to wait for other users to bookmark the same message
-TIMEOUT = 120
-MESSAGE_NOT_FOUND_ERROR = (
- "You must either provide a reference to a valid message, or reply to one."
- "\n\nThe lookup strategy for a message is as follows (in order):"
- "\n1. Lookup by '{channel ID}-{message ID}' (retrieved by shift-clicking on 'Copy ID')"
- "\n2. Lookup by message ID (the message **must** be in the current channel)"
- "\n3. Lookup by message URL"
-)
-
-class BookmarkTitleSelectionForm(discord.ui.Modal):
- """
- The form where a user can fill in a custom title for their bookmark & submit it.
-
- This form is only available when the command is invoked from a context menu.
- """
+class BookmarkForm(discord.ui.Modal):
+ """The form where a user can fill in a custom title for their bookmark & submit it."""
bookmark_title = discord.ui.TextInput(
label="Choose a title for your bookmark (optional)",
@@ -36,67 +21,47 @@ class BookmarkTitleSelectionForm(discord.ui.Modal):
default="Bookmark",
max_length=50,
min_length=0,
- required=False
+ required=False,
)
- def __init__(
- self,
- message: discord.Message,
- action_bookmark_function: Callable[[discord.TextChannel, discord.Member, discord.Message, str], None],
- ):
+ def __init__(self, message: discord.Message):
super().__init__(timeout=1000, title="Name your bookmark")
self.message = message
- self.action_bookmark = action_bookmark_function
async def on_submit(self, interaction: discord.Interaction) -> None:
"""Sends the bookmark embed to the user with the newly chosen title."""
title = self.bookmark_title.value or self.bookmark_title.default
- await self.action_bookmark(interaction.channel, interaction.user, self.message, title)
- embed = Bookmark.build_ephemeral_bookmark_embed(self.message)
- await interaction.response.send_message(embed=embed, ephemeral=True)
-
-
-class LinkTargetMessage(discord.ui.View):
- """The button that relays the user to the bookmarked message."""
-
- def __init__(self, target_message: discord.Message):
- super().__init__()
- self.add_item(discord.ui.Button(label="View Message", url=target_message.jump_url))
-
-
-class SendBookmark(discord.ui.View):
- """The button that sends the bookmark to other users."""
-
- def __init__(
- self,
- action_bookmark_function: Callable[[discord.TextChannel, discord.Member, discord.Message, str], None],
- author: discord.Member,
- channel: discord.TextChannel,
- target_message: discord.Message,
- title: str
- ):
- super().__init__()
-
- self.bookmark_function = action_bookmark_function
- self.clicked = [author.id]
- self.channel = channel
- self.target_message = target_message
- self.title = title
-
- @discord.ui.button(label="Receive Bookmark", style=discord.ButtonStyle.green)
- async def button_callback(self, interaction: discord.Interaction, button: discord.Button) -> None:
- """The button callback."""
- if interaction.user.id in self.clicked:
+ try:
+ await self.dm_bookmark(interaction, self.message, title)
+ except discord.Forbidden:
await interaction.response.send_message(
- "You have already received a bookmark to that message.",
+ embed=Bookmark.build_error_embed("Enable your DMs to receive the bookmark."),
ephemeral=True,
)
return
- self.clicked.append(interaction.user.id)
- await self.bookmark_function(self.channel, interaction.user, self.target_message, self.title)
+ await interaction.response.send_message(
+ embed=Bookmark.build_success_reply_embed(self.message),
+ ephemeral=True,
+ )
+
+ async def dm_bookmark(
+ self,
+ interaction: discord.Interaction,
+ target_message: discord.Message,
+ title: str,
+ ) -> None:
+ """
+ Sends the target_message as a bookmark to the interaction user's DMs.
- await interaction.response.send_message("You have received a bookmark to that message.", ephemeral=True)
+ Raises ``discord.Forbidden`` if the user's DMs are closed.
+ """
+ embed = Bookmark.build_bookmark_dm(target_message, title)
+ message_url_view = discord.ui.View().add_item(
+ discord.ui.Button(label="View Message", url=target_message.jump_url)
+ )
+ await interaction.user.send(embed=embed, view=message_url_view)
+ log.info(f"{interaction.user} bookmarked {target_message.jump_url} with title {title!r}")
class Bookmark(commands.Cog):
@@ -106,40 +71,24 @@ class Bookmark(commands.Cog):
self.bot = bot
self.book_mark_context_menu = discord.app_commands.ContextMenu(
name="Bookmark",
- callback=self._bookmark_context_menu_callback
+ callback=self._bookmark_context_menu_callback,
)
- self.bot.tree.add_command(self.book_mark_context_menu)
+ self.bot.tree.add_command(self.book_mark_context_menu, guild=discord.Object(bot.guild_id))
@staticmethod
- def build_bookmark_embed(target_message: discord.Message) -> discord.Embed:
- """Build the channel embed to the bookmark requester."""
+ def build_success_reply_embed(target_message: discord.Message) -> discord.Embed:
+ """Build the ephemeral reply embed to the bookmark requester."""
return discord.Embed(
description=(
- f"Click the button to be sent your very own bookmark to "
- f"[this message]({target_message.jump_url})."
- ),
- colour=Colours.soft_green,
- )
-
- @staticmethod
- def build_ephemeral_bookmark_embed(target_message: discord.Message) -> discord.Embed:
- """Build the ephemeral embed to the bookmark requester."""
- return discord.Embed(
- description=(
- f"A bookmark for [this message]({target_message.jump_url}) "
- f"has been successfully sent your way.\n"
+ f"A bookmark for [this message]({target_message.jump_url}) has been successfully sent your way."
),
colour=Colours.soft_green,
)
@staticmethod
def build_bookmark_dm(target_message: discord.Message, title: str) -> discord.Embed:
- """Build the embed to DM the bookmark requester."""
- embed = discord.Embed(
- title=title,
- description=target_message.content,
- colour=Colours.soft_green
- )
+ """Build the embed that is DM'd to the bookmark requester."""
+ embed = discord.Embed(title=title, description=target_message.content, colour=Colours.soft_green)
embed.set_author(
name=target_message.author,
icon_url=target_message.author.display_avatar.url,
@@ -153,85 +102,36 @@ class Bookmark(commands.Cog):
return discord.Embed(
title=random.choice(ERROR_REPLIES),
description=message,
- colour=Colours.soft_red
+ colour=Colours.soft_red,
)
- async def action_bookmark(
- self,
- channel: discord.TextChannel,
- member: discord.Member,
- target_message: discord.Message,
- title: str
- ) -> None:
- """
- Sends the given target_message as a bookmark to the member in DMs to the user.
-
- Send an error embed instead if the member has DMs disabled.
- """
- embed = self.build_bookmark_dm(target_message, title)
- try:
- await member.send(embed=embed, view=LinkTargetMessage(target_message))
- except discord.Forbidden:
- error_embed = self.build_error_embed(f"{member.mention}, please enable your DMs to receive the bookmark.")
- await channel.send(embed=error_embed)
- else:
- log.info(f"{member} bookmarked {target_message.jump_url} with title '{title}'")
-
async def _bookmark_context_menu_callback(self, interaction: discord.Interaction, message: discord.Message) -> None:
"""The callback that will be invoked upon using the bookmark's context menu command."""
permissions = interaction.channel.permissions_for(interaction.user)
- if not interaction.channel.guild:
- embed = Bookmark.build_error_embed("This command cannot be used in DMs.")
- await interaction.response.send_message(embed=embed)
- return
-
if not permissions.read_messages:
- log.info(f"{interaction.user} tried to bookmark a message in #{interaction.channel}"
- f"but has no permissions.")
- embed = Bookmark.build_error_embed("You don't have permission to view this channel.")
+ log.info(
+ f"{interaction.user} tried to bookmark a message in #{interaction.channel} but doesn't have permission."
+ )
+ embed = self.build_error_embed("You don't have permission to view this channel.")
await interaction.response.send_message(embed=embed)
return
- bookmark_title_form = BookmarkTitleSelectionForm(
- message=message,
- action_bookmark_function=self.action_bookmark
- )
+ bookmark_title_form = BookmarkForm(message=message)
await interaction.response.send_modal(bookmark_title_form)
@commands.group(name="bookmark", aliases=("bm", "pin"), invoke_without_command=True)
@commands.guild_only()
@whitelist_override(roles=(Roles.everyone,))
- async def bookmark(
- self,
- ctx: commands.Context,
- target_message: Optional[WrappedMessageConverter],
- *,
- title: str = "Bookmark"
- ) -> None:
- """
- Send the author a link to the specified message via DMs.
-
- Members can either give a message as an argument, or reply to a message.
-
- Bookmarks can subsequently be deleted by using the `bookmark delete` command in DMs.
- """
- target_message: Optional[discord.Message] = target_message or getattr(ctx.message.reference, "resolved", None)
- if target_message is None:
- raise commands.UserInputError(MESSAGE_NOT_FOUND_ERROR)
-
- permissions = ctx.channel.permissions_for(ctx.author)
- if not permissions.read_messages:
- log.info(f"{ctx.author} tried to bookmark a message in #{ctx.channel} but has no permissions.")
- embed = Bookmark.build_error_embed("You don't have permission to view this channel.")
- await ctx.send(embed=embed)
- return
-
- await self.action_bookmark(ctx.channel, ctx.author, target_message, title)
-
- view = SendBookmark(self.action_bookmark, ctx.author, ctx.channel, target_message, title)
- embed = self.build_bookmark_embed(target_message)
-
- await ctx.send(embed=embed, view=view)
+ @commands.cooldown(1, 30, commands.BucketType.channel)
+ async def bookmark(self, ctx: commands.Context) -> None:
+ """Teach the invoker how to use the new context-menu based command for a smooth migration."""
+ await ctx.send(
+ embed=self.build_error_embed(
+ "The bookmark text command has been replaced with a context menu command!\n\n"
+ "To bookmark a message simply right-click (press and hold on mobile) "
+ "on a message, open the 'Apps' menu, and click 'Bookmark'."
+ )
+ )
@bookmark.command(name="delete", aliases=("del", "rm"), root_aliases=("unbm", "unbookmark", "dmdelete", "dmdel"))
@whitelist_override(bypass_defaults=True, allow_dm=True)