aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/constants.py1
-rw-r--r--bot/converters.py25
-rw-r--r--bot/exts/fun/off_topic_names.py18
-rw-r--r--bot/exts/help_channels/_cog.py4
-rw-r--r--bot/exts/help_channels/_message.py33
-rw-r--r--bot/resources/tags/off-topic.md2
-rw-r--r--config-default.yml1
7 files changed, 73 insertions, 11 deletions
diff --git a/bot/constants.py b/bot/constants.py
index 8a93ff9cf..69bc82b89 100644
--- a/bot/constants.py
+++ b/bot/constants.py
@@ -326,6 +326,7 @@ class Icons(metaclass=YAMLGetter):
filtering: str
green_checkmark: str
+ green_questionmark: str
guild_update: str
hash_blurple: str
diff --git a/bot/converters.py b/bot/converters.py
index 0d9a519df..80ce99459 100644
--- a/bot/converters.py
+++ b/bot/converters.py
@@ -357,27 +357,38 @@ class Duration(DurationDelta):
class OffTopicName(Converter):
"""A converter that ensures an added off-topic name is valid."""
+ ALLOWED_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ!?'`-"
+
+ @classmethod
+ def translate_name(cls, name: str, *, from_unicode: bool = True) -> str:
+ """
+ Translates `name` into a format that is allowed in discord channel names.
+
+ If `from_unicode` is True, the name is translated from a discord-safe format, back to normalized text.
+ """
+ if from_unicode:
+ table = str.maketrans(cls.ALLOWED_CHARACTERS, '๐– ๐–ก๐–ข๐–ฃ๐–ค๐–ฅ๐–ฆ๐–ง๐–จ๐–ฉ๐–ช๐–ซ๐–ฌ๐–ญ๐–ฎ๐–ฏ๐–ฐ๐–ฑ๐–ฒ๐–ณ๐–ด๐–ต๐–ถ๐–ท๐–ธ๐–นวƒ๏ผŸโ€™โ€™-')
+ else:
+ table = str.maketrans('๐– ๐–ก๐–ข๐–ฃ๐–ค๐–ฅ๐–ฆ๐–ง๐–จ๐–ฉ๐–ช๐–ซ๐–ฌ๐–ญ๐–ฎ๐–ฏ๐–ฐ๐–ฑ๐–ฒ๐–ณ๐–ด๐–ต๐–ถ๐–ท๐–ธ๐–นวƒ๏ผŸโ€™โ€™-', cls.ALLOWED_CHARACTERS)
+
+ return name.translate(table)
+
async def convert(self, ctx: Context, argument: str) -> str:
"""Attempt to replace any invalid characters with their approximate Unicode equivalent."""
- allowed_characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ!?'`-"
-
# Chain multiple words to a single one
argument = "-".join(argument.split())
if not (2 <= len(argument) <= 96):
raise BadArgument("Channel name must be between 2 and 96 chars long")
- elif not all(c.isalnum() or c in allowed_characters for c in argument):
+ elif not all(c.isalnum() or c in self.ALLOWED_CHARACTERS for c in argument):
raise BadArgument(
"Channel name must only consist of "
"alphanumeric characters, minus signs or apostrophes."
)
# Replace invalid characters with unicode alternatives.
- table = str.maketrans(
- allowed_characters, '๐– ๐–ก๐–ข๐–ฃ๐–ค๐–ฅ๐–ฆ๐–ง๐–จ๐–ฉ๐–ช๐–ซ๐–ฌ๐–ญ๐–ฎ๐–ฏ๐–ฐ๐–ฑ๐–ฒ๐–ณ๐–ด๐–ต๐–ถ๐–ท๐–ธ๐–นวƒ๏ผŸโ€™โ€™-'
- )
- return argument.translate(table)
+ return self.translate_name(argument)
class ISODateTime(Converter):
diff --git a/bot/exts/fun/off_topic_names.py b/bot/exts/fun/off_topic_names.py
index 7fc93b88c..845b8175c 100644
--- a/bot/exts/fun/off_topic_names.py
+++ b/bot/exts/fun/off_topic_names.py
@@ -139,10 +139,20 @@ class OffTopicNames(Cog):
@has_any_role(*MODERATION_ROLES)
async def search_command(self, ctx: Context, *, query: OffTopicName) -> None:
"""Search for an off-topic name."""
- result = await self.bot.api_client.get('bot/off-topic-channel-names')
- in_matches = {name for name in result if query in name}
- close_matches = difflib.get_close_matches(query, result, n=10, cutoff=0.70)
- lines = sorted(f"โ€ข {name}" for name in in_matches.union(close_matches))
+ query = OffTopicName.translate_name(query, from_unicode=False).lower()
+
+ # Map normalized names to returned names for search purposes
+ result = {
+ OffTopicName.translate_name(name, from_unicode=False).lower(): name
+ for name in await self.bot.api_client.get('bot/off-topic-channel-names')
+ }
+
+ # Search normalized keys
+ in_matches = {name for name in result.keys() if query in name}
+ close_matches = difflib.get_close_matches(query, result.keys(), n=10, cutoff=0.70)
+
+ # Send Results
+ lines = sorted(f"โ€ข {result[name]}" for name in in_matches.union(close_matches))
embed = Embed(
title="Query results",
colour=Colour.blue()
diff --git a/bot/exts/help_channels/_cog.py b/bot/exts/help_channels/_cog.py
index 0995c8a79..6abf99810 100644
--- a/bot/exts/help_channels/_cog.py
+++ b/bot/exts/help_channels/_cog.py
@@ -102,6 +102,10 @@ class HelpChannels(commands.Cog):
await _cooldown.revoke_send_permissions(message.author, self.scheduler)
await _message.pin(message)
+ try:
+ await _message.dm_on_open(message)
+ except Exception as e:
+ log.warning("Error occurred while sending DM:", exc_info=e)
# Add user with channel for dormant check.
await _caches.claimants.set(message.channel.id, message.author.id)
diff --git a/bot/exts/help_channels/_message.py b/bot/exts/help_channels/_message.py
index 2bbd4bdd6..36388f9bd 100644
--- a/bot/exts/help_channels/_message.py
+++ b/bot/exts/help_channels/_message.py
@@ -1,4 +1,5 @@
import logging
+import textwrap
import typing as t
from datetime import datetime
@@ -92,6 +93,38 @@ async def is_empty(channel: discord.TextChannel) -> bool:
return False
+async def dm_on_open(message: discord.Message) -> None:
+ """
+ DM claimant with a link to the claimed channel's first message, with a 100 letter preview of the message.
+
+ Does nothing if the user has DMs disabled.
+ """
+ embed = discord.Embed(
+ title="Help channel opened",
+ description=f"You claimed {message.channel.mention}.",
+ colour=bot.constants.Colours.bright_green,
+ timestamp=message.created_at,
+ )
+
+ embed.set_thumbnail(url=constants.Icons.green_questionmark)
+ formatted_message = textwrap.shorten(message.content, width=100, placeholder="...")
+ if formatted_message:
+ embed.add_field(name="Your message", value=formatted_message, inline=False)
+ embed.add_field(
+ name="Conversation",
+ value=f"[Jump to message!]({message.jump_url})",
+ inline=False,
+ )
+
+ try:
+ await message.author.send(embed=embed)
+ log.trace(f"Sent DM to {message.author.id} after claiming help channel.")
+ except discord.errors.Forbidden:
+ log.trace(
+ f"Ignoring to send DM to {message.author.id} after claiming help channel: DMs disabled."
+ )
+
+
async def notify(channel: discord.TextChannel, last_notification: t.Optional[datetime]) -> t.Optional[datetime]:
"""
Send a message in `channel` notifying about a lack of available help channels.
diff --git a/bot/resources/tags/off-topic.md b/bot/resources/tags/off-topic.md
index c7f98a813..6a864a1d5 100644
--- a/bot/resources/tags/off-topic.md
+++ b/bot/resources/tags/off-topic.md
@@ -6,3 +6,5 @@ There are three off-topic channels:
โ€ข <#463035268514185226>
Their names change randomly every 24 hours, but you can always find them under the `OFF-TOPIC/GENERAL` category in the channel list.
+
+Please read our [off-topic etiquette](https://pythondiscord.com/pages/resources/guides/off-topic-etiquette/) before participating in conversations.
diff --git a/config-default.yml b/config-default.yml
index 8e9a29a51..7d9afaa0e 100644
--- a/config-default.yml
+++ b/config-default.yml
@@ -90,6 +90,7 @@ style:
filtering: "https://cdn.discordapp.com/emojis/472472638594482195.png"
green_checkmark: "https://raw.githubusercontent.com/python-discord/branding/master/icons/checkmark/green-checkmark-dist.png"
+ green_questionmark: "https://raw.githubusercontent.com/python-discord/branding/master/icons/checkmark/green-question-mark-dist.png"
guild_update: "https://cdn.discordapp.com/emojis/469954765141442561.png"
hash_blurple: "https://cdn.discordapp.com/emojis/469950142942806017.png"