From 6ccbb944a50058cea74bfdfe855a538b09ab67b7 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Wed, 15 Jul 2020 07:22:59 +0200 Subject: Restore DM user caching. This reverts commit 042f472a --- bot/cogs/dm_relay.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/bot/cogs/dm_relay.py b/bot/cogs/dm_relay.py index f62d6105e..9a68b5341 100644 --- a/bot/cogs/dm_relay.py +++ b/bot/cogs/dm_relay.py @@ -1,4 +1,5 @@ import logging +from typing import Optional import discord from discord import Color @@ -7,6 +8,7 @@ from discord.ext.commands import Cog from bot import constants from bot.bot import Bot +from bot.utils import RedisCache from bot.utils.checks import in_whitelist_check, with_role_check from bot.utils.messages import send_attachments from bot.utils.webhooks import send_webhook @@ -17,6 +19,9 @@ log = logging.getLogger(__name__) class DMRelay(Cog): """Relay direct messages to and from the bot.""" + # RedisCache[str, t.Union[discord.User.id, discord.Member.id]] + dm_cache = RedisCache() + def __init__(self, bot: Bot): self.bot = bot self.webhook_id = constants.Webhooks.dm_log @@ -24,11 +29,11 @@ class DMRelay(Cog): self.bot.loop.create_task(self.fetch_webhook()) @commands.command(aliases=("reply",)) - async def send_dm(self, ctx: commands.Context, member: discord.Member, *, message: str) -> None: + async def send_dm(self, ctx: commands.Context, member: Optional[discord.Member], *, message: str) -> None: """ Allows you to send a DM to a user from the bot. - A `member` must be provided. + If `member` is not provided, it will send to the last user who DM'd the bot. This feature should be used extremely sparingly. Use ModMail if you need to have a serious conversation with a user. This is just for responding to extraordinary DMs, having a little @@ -36,11 +41,21 @@ class DMRelay(Cog): NOTE: This feature will be removed if it is overused. """ - try: - await member.send(message) - await ctx.message.add_reaction("✅") - return + user_id = await self.dm_cache.get("last_user") + last_dm_user = ctx.guild.get_member(user_id) if user_id else None + try: + if member: + await member.send(message) + await ctx.message.add_reaction("✅") + return + elif last_dm_user: + await last_dm_user.send(message) + await ctx.message.add_reaction("✅") + return + else: + log.debug("This bot has never gotten a DM, or the RedisCache has been cleared.") + await ctx.message.add_reaction("❌") except discord.errors.Forbidden: log.debug("User has disabled DMs.") await ctx.message.add_reaction("❌") @@ -68,6 +83,7 @@ class DMRelay(Cog): username=message.author.display_name, avatar_url=message.author.avatar_url ) + await self.dm_cache.set("last_user", message.author.id) # Handle any attachments if message.attachments: -- cgit v1.2.3 From 226eb68a4d397c14c68566f60a2de4a3704cf696 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Wed, 15 Jul 2020 07:30:02 +0200 Subject: Add the user ID to the username in dm relays. Without this, it is difficult to know precisely who the user that is DMing us is, which might be useful to us. https://github.com/python-discord/bot/issues/1041 --- bot/cogs/dm_relay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/cogs/dm_relay.py b/bot/cogs/dm_relay.py index 9a68b5341..d3637d34b 100644 --- a/bot/cogs/dm_relay.py +++ b/bot/cogs/dm_relay.py @@ -80,7 +80,7 @@ class DMRelay(Cog): await send_webhook( webhook=self.webhook, content=message.clean_content, - username=message.author.display_name, + username=f"{message.author.display_name} ({message.author.id})", avatar_url=message.author.avatar_url ) await self.dm_cache.set("last_user", message.author.id) -- cgit v1.2.3 From ed6d848e3cd5cf355b9702e9c8df08c063c11a47 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Wed, 15 Jul 2020 07:33:48 +0200 Subject: Add some stats for DMs sent and received. https://github.com/python-discord/bot/issues/1041 --- bot/cogs/dm_relay.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bot/cogs/dm_relay.py b/bot/cogs/dm_relay.py index d3637d34b..edfcccf6d 100644 --- a/bot/cogs/dm_relay.py +++ b/bot/cogs/dm_relay.py @@ -48,10 +48,12 @@ class DMRelay(Cog): if member: await member.send(message) await ctx.message.add_reaction("✅") + self.bot.stats.incr("dm_relay.dm_sent") return elif last_dm_user: await last_dm_user.send(message) await ctx.message.add_reaction("✅") + self.bot.stats.incr("dm_relay.dm_sent") return else: log.debug("This bot has never gotten a DM, or the RedisCache has been cleared.") @@ -84,6 +86,7 @@ class DMRelay(Cog): avatar_url=message.author.avatar_url ) await self.dm_cache.set("last_user", message.author.id) + self.bot.stats.incr("dm_relay.dm_received") # Handle any attachments if message.attachments: -- cgit v1.2.3 From 90d2a77becb39d6b3c0056ea7c05b4a9e4d16f50 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Wed, 15 Jul 2020 10:15:08 +0200 Subject: Ves' refactor Co-authored-by: Sebastiaan Zeeff <33516116+SebastiaanZ@users.noreply.github.com> --- bot/cogs/dm_relay.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/bot/cogs/dm_relay.py b/bot/cogs/dm_relay.py index edfcccf6d..0c3eddf42 100644 --- a/bot/cogs/dm_relay.py +++ b/bot/cogs/dm_relay.py @@ -41,23 +41,24 @@ class DMRelay(Cog): NOTE: This feature will be removed if it is overused. """ - user_id = await self.dm_cache.get("last_user") - last_dm_user = ctx.guild.get_member(user_id) if user_id else None + if not member: + user_id = await self.dm_cache.get("last_user") + member = ctx.guild.get_member(user_id) if user_id else None + + # If we still don't have a Member at this point, give up + if not member: + log.debug("This bot has never gotten a DM, or the RedisCache has been cleared.") + await ctx.message.add_reaction("❌") + return try: - if member: - await member.send(message) - await ctx.message.add_reaction("✅") - self.bot.stats.incr("dm_relay.dm_sent") - return - elif last_dm_user: - await last_dm_user.send(message) - await ctx.message.add_reaction("✅") - self.bot.stats.incr("dm_relay.dm_sent") - return - else: - log.debug("This bot has never gotten a DM, or the RedisCache has been cleared.") - await ctx.message.add_reaction("❌") + await member.send(message) + except discord.errors.Forbidden: + log.debug("User has disabled DMs.") + await ctx.message.add_reaction("❌") + else: + await ctx.message.add_reaction("✅") + self.bot.stats.incr("dm_relay.dm_sent") except discord.errors.Forbidden: log.debug("User has disabled DMs.") await ctx.message.add_reaction("❌") -- cgit v1.2.3 From 403572b83cf3faea9068a25cb09e809d993c1514 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Wed, 15 Jul 2020 10:39:07 +0200 Subject: Create a UserMentionOrID converter. When we're using the !reply command, using a regular UserConverter is somewhat problematic. For example, if I wanted to send the message "lemon loves you", then I'd try to write `!reply lemon loves you` - however, the optional User converter would then try to convert `lemon` into a User, which it would successfully do since there's like 60 lemons on our server. As a result, the message "loves you" would be sent to a user called lemon.. god knows which one. To solve this bit of ambiguity, I introduce a new converter which only converts user mentions or user IDs into User, not strings that may be intended as part of the message you are sending. https://github.com/python-discord/bot/issues/1041 --- bot/cogs/dm_relay.py | 3 ++- bot/converters.py | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/bot/cogs/dm_relay.py b/bot/cogs/dm_relay.py index 0c3eddf42..c5a3dba22 100644 --- a/bot/cogs/dm_relay.py +++ b/bot/cogs/dm_relay.py @@ -8,6 +8,7 @@ from discord.ext.commands import Cog from bot import constants from bot.bot import Bot +from bot.converters import UserMentionOrID from bot.utils import RedisCache from bot.utils.checks import in_whitelist_check, with_role_check from bot.utils.messages import send_attachments @@ -29,7 +30,7 @@ class DMRelay(Cog): self.bot.loop.create_task(self.fetch_webhook()) @commands.command(aliases=("reply",)) - async def send_dm(self, ctx: commands.Context, member: Optional[discord.Member], *, message: str) -> None: + async def send_dm(self, ctx: commands.Context, member: Optional[UserMentionOrID], *, message: str) -> None: """ Allows you to send a DM to a user from the bot. diff --git a/bot/converters.py b/bot/converters.py index 898822165..7c62f92dd 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -330,6 +330,28 @@ def proxy_user(user_id: str) -> discord.Object: return user +class UserMentionOrID(UserConverter): + """ + Converts to a `discord.User`, but only if a mention or userID is provided. + + Unlike the default `UserConverter`, it does allow conversion from name, or name#descrim. + + This is useful in cases where that lookup strategy would lead to ambiguity. + """ + + async def convert(self, ctx: Context, argument: str) -> discord.User: + """Convert the `arg` to a `discord.User`.""" + print(argument) + match = self._get_id_match(argument) or re.match(r'<@!?([0-9]+)>$', argument) + + print(match) + + if match is not None: + return await super().convert(ctx, argument) + else: + raise BadArgument(f"`{argument}` is not a User mention or a User ID.") + + class FetchedUser(UserConverter): """ Converts to a `discord.User` or, if it fails, a `discord.Object`. -- cgit v1.2.3 From 80c1dbb240b744ceed5d1ea56c44c91d0014c304 Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Wed, 15 Jul 2020 10:44:11 +0200 Subject: How did that except except block get in? Weird. https://github.com/python-discord/bot/issues/1041 --- bot/cogs/dm_relay.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bot/cogs/dm_relay.py b/bot/cogs/dm_relay.py index c5a3dba22..0dc15d4b1 100644 --- a/bot/cogs/dm_relay.py +++ b/bot/cogs/dm_relay.py @@ -60,9 +60,6 @@ class DMRelay(Cog): else: await ctx.message.add_reaction("✅") self.bot.stats.incr("dm_relay.dm_sent") - except discord.errors.Forbidden: - log.debug("User has disabled DMs.") - await ctx.message.add_reaction("❌") async def fetch_webhook(self) -> None: """Fetches the webhook object, so we can post to it.""" -- cgit v1.2.3 From 14141a25bb87c298afae89886cb0ca3df65b9dee Mon Sep 17 00:00:00 2001 From: Leon Sandøy Date: Wed, 15 Jul 2020 12:59:48 +0200 Subject: Oops, these prints shouldn't be here. https://github.com/python-discord/bot/issues/1041 --- bot/converters.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bot/converters.py b/bot/converters.py index 7c62f92dd..4a0633951 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -341,11 +341,8 @@ class UserMentionOrID(UserConverter): async def convert(self, ctx: Context, argument: str) -> discord.User: """Convert the `arg` to a `discord.User`.""" - print(argument) match = self._get_id_match(argument) or re.match(r'<@!?([0-9]+)>$', argument) - print(match) - if match is not None: return await super().convert(ctx, argument) else: -- cgit v1.2.3