Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
6 changes: 3 additions & 3 deletions cogs/cOREmands.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import discord
from discord.ext import commands

from util import app_is_staff, is_staff, create_deletion_embed, reply
from util import app_is_staff, is_staff, create_deletion_embed, reply, escape_nickname


class COREmands(commands.Cog):
Expand Down Expand Up @@ -35,10 +35,10 @@ async def trust(self, ctx, member: discord.Member):
role = ctx.guild.get_role(self.bot.config["roles"]["trusted"])
if role in member.roles:
await member.remove_roles(role)
await reply(ctx, f"{member.display_name} is no longer Trusted.")
await reply(ctx, f"{escape_nickname(member.display_name)} is no longer Trusted.")
else:
await member.add_roles(role)
await reply(ctx, f"{member.display_name} is now Trusted.")
await reply(ctx, f"{escape_nickname(member.display_name)} is now Trusted.")

async def setup(bot):
await bot.add_cog(COREmands(bot))
4 changes: 2 additions & 2 deletions cogs/errorhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from discord.ext import commands

from util import NoRelayException, reply
from util import NoRelayException, reply, user_log_repr


class ErrorHandler(commands.Cog):
Expand Down Expand Up @@ -34,7 +34,7 @@ async def respond(message):
)
elif isinstance(error, commands.CommandNotFound):
self.bot.logger.info(
f"User '{ctx.author.display_name}' attempted to run an unrecognized command: '{ctx.message.content[1:]}'"
f"User {user_log_repr(ctx.author)} attempted to run an unrecognized command: '{ctx.message.content[1:]}'"
)
await respond("Unrecognized command :'(")
elif isinstance(error, commands.CommandOnCooldown):
Expand Down
4 changes: 2 additions & 2 deletions cogs/moderation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from discord.ext import commands, tasks
import typing

from util import is_staff, app_is_staff, create_deletion_embed, reformat_relay_chat
from util import is_staff, app_is_staff, create_deletion_embed, reformat_relay_chat, escape_nickname
from timeutil import UserFriendlyTime

class Moderation(commands.Cog):
Expand Down Expand Up @@ -97,7 +97,7 @@ async def tempban(self, ctx, user: typing.Union[discord.Member, discord.User], *
embed.set_thumbnail(url="https://i.imgflip.com/44o9ir.png")
embed.add_field(name="Staff Member", value=ctx.author.mention, inline=False)
embed.add_field(name="User", value=user.mention, inline=True)
embed.add_field(name="Display Name", value=user.display_name, inline=True)
embed.add_field(name="Display Name", value=escape_nickname(user.display_name), inline=True)
embed.add_field(name="Reason", value=reason if reason else "No reason provided", inline=False)
embed.timestamp = ctx.message.created_at

Expand Down
6 changes: 4 additions & 2 deletions cogs/notifications.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import discord
from discord.ext import commands

from util import escape_nickname


class RoleButton(discord.ui.Button):
def __init__(self, role):
Expand All @@ -13,13 +15,13 @@ async def callback(self, interaction: discord.Interaction):
if self.role in interaction.user.roles:
await interaction.user.remove_roles(self.role)
await interaction.response.send_message(
f"{interaction.user.display_name}, you are no longer subscribed to {self.role.name} notifications.",
f"{escape_nickname(interaction.user.display_name)}, you are no longer subscribed to {self.role.name} notifications.",
ephemeral=True,
)
else:
await interaction.user.add_roles(self.role)
await interaction.response.send_message(
f"{interaction.user.display_name}, you are now subscribed to {self.role.name} notifications.",
f"{escape_nickname(interaction.user.display_name)}, you are now subscribed to {self.role.name} notifications.",
ephemeral=True,
)

Expand Down
9 changes: 5 additions & 4 deletions cogs/randcommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from fractal import fractal
from spirograph import spirograph
from brainfuck import process_brainfuck
from util import is_staff, BaseConversionError, baseconvert, reply
from util import is_staff, BaseConversionError, baseconvert, reply, escape_nickname


class RandCommands(commands.Cog):
Expand All @@ -42,7 +42,7 @@ async def convert_func(ctx, number: str):
# otherwise keep the generic text.
except BaseConversionError as err:
raise err from None
except ValueError as e:
except ValueError:
await reply(ctx, f"Invalid input number for base {from_base}")

for from_base, from_value in bases.items():
Expand All @@ -63,7 +63,8 @@ async def ping(self, ctx):
message = await reply(ctx, "Testing...")
latency = (perf_counter() - start) * 1000
await message.edit(
content=f"{ctx.author.display_name}: Pong!\nLatency: {latency:.2f}ms\n"
content=f"{escape_nickname(ctx.author.display_name)}: Pong!\n"
f"Latency: {latency:.2f}ms\n"
f"API Latency: {self.bot.latency * 1000:.2f}ms"
)

Expand Down Expand Up @@ -347,7 +348,7 @@ async def spirograph(self, ctx, seed: str):
@commands.command(help="Be mean to someone. >:D")
async def insult(self, ctx, target: str = None):
if target is None:
target = ctx.author.display_name
target = escape_nickname(ctx.author.display_name)
message = choice(self.bot.config["insults"])
await reply(ctx, message.format(user=target))

Expand Down
8 changes: 4 additions & 4 deletions cogs/reminders.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from discord.ext import commands, tasks
from datetime import datetime, timedelta

from util import is_discord_member, return_or_truncate
from util import escape_nickname, is_discord_member, return_or_truncate
from timeutil import UserFriendlyTime
from paginator import EmbedPaginatorSession

Expand Down Expand Up @@ -41,10 +41,10 @@ async def my_reminders(self, ctx):
"""List all reminders set by the user."""
reminders = await self.bot.database.get_reminders(ctx.author.id)
if not reminders:
return await ctx.reply(f"{ctx.author.display_name}: You have no reminders set.")
return await ctx.reply(f"{escape_nickname(ctx.author.display_name)}: You have no reminders set.")

if len(reminders) > 5:
embeds = [discord.Embed(title=f"{ctx.author.display_name}'s Reminders", color=discord.Color.blue()) for _ in range((len(reminders) - 1) // 5 + 1)]
embeds = [discord.Embed(title=f"{escape_nickname(ctx.author.display_name)}'s Reminders", color=discord.Color.blue()) for _ in range((len(reminders) - 1) // 5 + 1)]
for i, reminder in enumerate(reminders):
embeds[i // 5].add_field(
name=f"Reminder at {reminder[2].strftime('%Y-%m-%d %H:%M:%S')}",
Expand All @@ -54,7 +54,7 @@ async def my_reminders(self, ctx):
paginator = EmbedPaginatorSession(ctx, *embeds)
await paginator.run()
else:
embed = discord.Embed(title=f"{ctx.author.display_name}'s Reminders", color=discord.Color.blue())
embed = discord.Embed(title=f"{escape_nickname(ctx.author.display_name)}'s Reminders", color=discord.Color.blue())
for message, _, timestamp in reminders:
embed.add_field(
name=f"Reminder at {timestamp.strftime('%Y-%m-%d %H:%M:%S')}",
Expand Down
4 changes: 2 additions & 2 deletions cogs/timers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import discord
from discord.ext import commands

from util import is_discord_member, reply
from util import is_discord_member, reply, escape_nickname


def pretty_timedelta(delta):
Expand Down Expand Up @@ -61,7 +61,7 @@ async def list_timers(self, ctx, member: discord.Member = None):
if member == ctx.author:
await reply(ctx, f"Your timers:\n{timers}")
else:
await reply(ctx, f"{member.display_name}'s timers:\n{timers}")
await reply(ctx, f"{escape_nickname(member.display_name)}'s timers:\n{timers}")
else:
await reply(ctx, "No timers found.")

Expand Down
11 changes: 6 additions & 5 deletions patrick.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
from logger import StreamLogFormatter, setup_logger
from util import (find_automod_matches, is_admin, load_automod_regexes,
process_custom_command, reformat_relay_chat, split_list,
reply, create_automod_embed, RelayMember)
reply, create_automod_embed, RelayMember, escape_nickname,
user_log_repr)

load_dotenv(Path(__file__).parent / ".env")
TOKEN: str = getenv("TOKEN")
Expand Down Expand Up @@ -218,7 +219,7 @@ async def on_message(self, message: discord.Message) -> None:
if message.guild is not None and message.content.startswith("/link"):
# If the message starts with /link, it's probably someone trying to link their account but not selecting the command from the popup.
await message.channel.send(
f"{message.author.display_name}: Please use the `/link` command from the command popup as you type. Do not type it out manually."
f"{escape_nickname(message.author.display_name)}: Please use the `/link` command from the command popup as you type. Do not type it out manually."
)
await message.delete()
return
Expand All @@ -229,7 +230,7 @@ async def on_message(self, message: discord.Message) -> None:
matches = find_automod_matches(self, part)
if matches:
logger.info(
f"Automod triggered for user {message.author.display_name} with message {message.content}"
f"Automod triggered for user {user_log_repr(message.author)} with message {message.content}"
Comment thread
JoBeGaming marked this conversation as resolved.
)
channel = message.guild.get_channel(
self.config["channels"]["automod"]
Expand Down Expand Up @@ -269,15 +270,15 @@ async def process_commands(self, message: discord.Message) -> None:
else:
# A prefix was found, but no (custom) command was found. This means the user is trying to run a command that does not exist.
self.logger.info(
f"User '{ctx.author.display_name}' attempted to run an unrecognized command: '{ctx.message.content[1:]}'"
f"User {user_log_repr(ctx.author)} attempted to run an unrecognized command: '{ctx.message.content[1:]}'"
)
return await reply(ctx, "Unrecognized command :'(")

if ctx.valid:
# The context is valid when a command and prefix was found.
# This is provided by discord.py and ensures that the context is valid for regular command processing
self.logger.info(
f"User '{message.author.display_name}' ran command '{ctx.command.name}'"
f"User {user_log_repr(message.author)} ran command '{ctx.command.name}'"
)
await self.database.add_command_history(
message.author.display_name, ctx.command.name
Expand Down
32 changes: 27 additions & 5 deletions util.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
from discord.ext import commands


DISCORD_NICKNAME_ESCAPE_RE = re.compile(r'([\\*#_`>~|\[\]()-])')


class NoRelayException(Exception):
...

Expand All @@ -26,6 +29,23 @@ class RelayMember(discord.Member):
"""


def user_log_repr(user: discord.User | discord.Member) -> str:
"""
Create a formatted string using the un-escaped nickname as well as the user
id, so log messages are the same as in chattore.
"""

return f"'{user.display_name}' ({user.id})"


def escape_nickname(name: str) -> str:
"""
Escape all characters in a discord nickname so they don't convert to markdown.
"""

return DISCORD_NICKNAME_ESCAPE_RE.sub(r"\\\1", name)


def return_or_truncate(text, max_length):
"""Takes a string and truncates it to a maximum length, adding ellipsis if truncated.
If the string is shorter than the maximum length, it returns the original string.
Expand Down Expand Up @@ -63,7 +83,7 @@ def reformat_relay_chat(bot, message) -> typing.Optional[discord.Message]:
author_name, content = match.groups()
message.author = copy(message.author)
message.author.__class__ = RelayMember
message.author.nick = author_name
message.author.nick = author_name.replace("\\", "")
message.content = content
return message
return None
Expand All @@ -85,12 +105,14 @@ async def process_custom_command(bot, message) -> bool:
for prefix in bot.command_prefix:
if message.content.removeprefix(prefix) in commands:
bot.logger.info(
f"User '{message.author.display_name}' ran custom command '{message.content[1:]}'"
f"User {user_log_repr(message.author)} ran custom command '{message.content[1:]}'"
Comment thread
JoBeGaming marked this conversation as resolved.
)
await message.channel.send(
f"{message.author.display_name}: {choice(commands[message.content.removeprefix(prefix)])}"
f"{escape_nickname(message.author.display_name)}: {choice(commands[message.content.removeprefix(prefix)])}"
)
await bot.database.add_command_history(
# No need to escape name here, this is not sent immediately. Also, it might
# cause problems with the current state of the DB.
message.author.display_name, message.content.removeprefix(prefix)
)
return True
Expand Down Expand Up @@ -327,7 +349,7 @@ async def create_deletion_embed(
embed.set_thumbnail(url="https://i.imgflip.com/44o9ir.png")
embed.add_field(name="Staff Member", value=staff.mention, inline=False)
embed.add_field(name="User", value=message.author.mention, inline=True)
embed.add_field(name="Display Name", value=message.author.display_name, inline=True)
embed.add_field(name="Display Name", value=escape_nickname(message.author.display_name), inline=True)
embed.add_field(name="Reason", value=reason, inline=False)
if len(message.message_snapshots) > 0:
embed.add_field(
Expand Down Expand Up @@ -408,4 +430,4 @@ async def reply(ctx, message=None, is_reply=False, is_silent=False, **kwargs):
if message is None:
message = ""
target = ctx.reply if is_reply else ctx.send
return await target(f"{ctx.author.display_name}: {message}", silent=is_silent, **kwargs)
return await target(f"{escape_nickname(ctx.author.display_name)}: {message}", silent=is_silent, **kwargs)