aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar ToxicKidz <[email protected]>2021-05-15 12:10:29 -0400
committerGravatar ToxicKidz <[email protected]>2021-05-15 12:10:29 -0400
commit8dd9e9cebd2496dc2e7e82569deb2fa9f1a5f89f (patch)
treeb763714dbd91578e15debd741921a2e604bd6c8b
parentchore: Reformat bot/utils/__init__.py (diff)
parentMerge pull request #736 from python-discord/concurrency-action (diff)
fix: Resolve merge conflicts again
-rw-r--r--.github/workflows/build.yaml4
-rw-r--r--.github/workflows/lint.yaml3
-rw-r--r--.github/workflows/sentry_release.yaml4
-rw-r--r--.github/workflows/status_embed.yaml4
-rw-r--r--bot/exts/evergreen/bookmark.py125
-rw-r--r--bot/utils/converters.py3
6 files changed, 119 insertions, 24 deletions
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index baa046ce..e857a6cf 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -8,6 +8,10 @@ on:
types:
- completed
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
build:
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push'
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
index 7f157da3..9e9cbbbf 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/lint.yaml
@@ -6,6 +6,9 @@ on:
- main
pull_request:
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
jobs:
lint:
diff --git a/.github/workflows/sentry_release.yaml b/.github/workflows/sentry_release.yaml
index 3d15e01e..c1073386 100644
--- a/.github/workflows/sentry_release.yaml
+++ b/.github/workflows/sentry_release.yaml
@@ -5,6 +5,10 @@ on:
branches:
- main
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
create_sentry_release:
runs-on: ubuntu-latest
diff --git a/.github/workflows/status_embed.yaml b/.github/workflows/status_embed.yaml
index 28caa8c2..737efe00 100644
--- a/.github/workflows/status_embed.yaml
+++ b/.github/workflows/status_embed.yaml
@@ -8,6 +8,10 @@ on:
types:
- completed
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
status_embed:
# We send the embed in the following situations:
diff --git a/bot/exts/evergreen/bookmark.py b/bot/exts/evergreen/bookmark.py
index f0fad0ea..29915627 100644
--- a/bot/exts/evergreen/bookmark.py
+++ b/bot/exts/evergreen/bookmark.py
@@ -1,3 +1,4 @@
+import asyncio
import logging
import random
@@ -5,15 +6,84 @@ import discord
from discord.ext import commands
from bot.bot import Bot
-from bot.constants import Colours, ERROR_REPLIES, Emojis, Icons
+from bot.constants import Colours, ERROR_REPLIES, Icons
from bot.utils.converters import WrappedMessageConverter
log = logging.getLogger(__name__)
+# Number of seconds to wait for other users to bookmark the same message
+TIMEOUT = 120
+BOOKMARK_EMOJI = "📌"
+
class Bookmark(commands.Cog):
"""Creates personal bookmarks by relaying a message link to the user's DMs."""
+ def __init__(self, bot: Bot):
+ self.bot = bot
+
+ @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
+ )
+ embed.add_field(
+ name="Wanna give it a visit?",
+ value=f"[Visit original message]({target_message.jump_url})"
+ )
+ embed.set_author(name=target_message.author, icon_url=target_message.author.avatar_url)
+ embed.set_thumbnail(url=Icons.bookmark)
+
+ return embed
+
+ @staticmethod
+ def build_error_embed(user: discord.Member) -> discord.Embed:
+ """Builds an error embed for when a bookmark requester has DMs disabled."""
+ return discord.Embed(
+ title=random.choice(ERROR_REPLIES),
+ description=f"{user.mention}, please enable your DMs to receive the bookmark.",
+ colour=Colours.soft_red
+ )
+
+ async def action_bookmark(
+ self,
+ channel: discord.TextChannel,
+ user: discord.Member,
+ target_message: discord.Message,
+ title: str
+ ) -> None:
+ """Sends the bookmark DM, or sends an error embed when a user bookmarks a message."""
+ try:
+ embed = self.build_bookmark_dm(target_message, title)
+ await user.send(embed=embed)
+ except discord.Forbidden:
+ error_embed = self.build_error_embed(user)
+ await channel.send(embed=error_embed)
+ else:
+ log.info(f"{user} bookmarked {target_message.jump_url} with title '{title}'")
+
+ @staticmethod
+ async def send_reaction_embed(
+ channel: discord.TextChannel,
+ target_message: discord.Message
+ ) -> discord.Message:
+ """Sends an embed, with a reaction, so users can react to bookmark the message too."""
+ message = await channel.send(
+ embed=discord.Embed(
+ description=(
+ f"React with {BOOKMARK_EMOJI} to be sent your very own bookmark to "
+ f"[this message]({target_message.jump_url})."
+ ),
+ colour=Colours.soft_green
+ )
+ )
+
+ await message.add_reaction(BOOKMARK_EMOJI)
+ return message
+
@commands.command(name="bookmark", aliases=("bm", "pin"))
async def bookmark(
self,
@@ -35,29 +105,40 @@ class Bookmark(commands.Cog):
await ctx.send(embed=embed)
return
- embed = discord.Embed(
- title=title,
- colour=Colours.soft_green,
- description=target_message.content
- )
- embed.add_field(name="Wanna give it a visit?", value=f"[Visit original message]({target_message.jump_url})")
- embed.set_author(name=target_message.author, icon_url=target_message.author.avatar_url)
- embed.set_thumbnail(url=Icons.bookmark)
-
- try:
- await ctx.author.send(embed=embed)
- except discord.Forbidden:
- error_embed = discord.Embed(
- title=random.choice(ERROR_REPLIES),
- description=f"{ctx.author.mention}, please enable your DMs to receive the bookmark.",
- colour=Colours.soft_red
+ def event_check(reaction: discord.Reaction, user: discord.Member) -> bool:
+ """Make sure that this reaction is what we want to operate on."""
+ return (
+ # Conditions for a successful pagination:
+ all((
+ # Reaction is on this message
+ reaction.message.id == reaction_message.id,
+ # User has not already bookmarked this message
+ user.id not in bookmarked_users,
+ # Reaction is the `BOOKMARK_EMOJI` emoji
+ str(reaction.emoji) == BOOKMARK_EMOJI,
+ # Reaction was not made by the Bot
+ user.id != self.bot.user.id
+ ))
)
- await ctx.send(embed=error_embed)
- else:
- log.info(f"{ctx.author} bookmarked {target_message.jump_url} with title '{title}'")
- await ctx.message.add_reaction(Emojis.envelope)
+ await self.action_bookmark(ctx.channel, ctx.author, target_message, title)
+
+ # Keep track of who has already bookmarked, so users can't spam reactions and cause loads of DMs
+ bookmarked_users = [ctx.author.id]
+ reaction_message = await self.send_reaction_embed(ctx.channel, target_message)
+
+ while True:
+ try:
+ _, user = await self.bot.wait_for("reaction_add", timeout=TIMEOUT, check=event_check)
+ except asyncio.TimeoutError:
+ log.debug("Timed out waiting for a reaction")
+ break
+ log.trace(f"{user} has successfully bookmarked from a reaction, attempting to DM them.")
+ await self.action_bookmark(ctx.channel, user, target_message, title)
+ bookmarked_users.append(user.id)
+
+ await reaction_message.delete()
def setup(bot: Bot) -> None:
"""Load the Bookmark cog."""
- bot.add_cog(Bookmark())
+ bot.add_cog(Bookmark(bot))
diff --git a/bot/utils/converters.py b/bot/utils/converters.py
index 9e9616d8..fe2c980c 100644
--- a/bot/utils/converters.py
+++ b/bot/utils/converters.py
@@ -8,8 +8,7 @@ from discord.ext import commands
class WrappedMessageConverter(commands.MessageConverter):
"""A converter that handles embed-suppressed links like <http://example.com>."""
- @staticmethod
- async def convert(ctx: commands.Context, argument: str) -> discord.Message:
+ async def convert(self, ctx: commands.Context, argument: str) -> discord.Message:
"""Wrap the commands.MessageConverter to handle <> delimited message links."""
# It's possible to wrap a message in [<>] as well, and it's supported because its easy
if argument.startswith("[") and argument.endswith("]"):