d.py 2.3 / pomelo changes (#6130)

Co-authored-by: Michael Oliveira <34169552+Flame442@users.noreply.github.com>
This commit is contained in:
Jakub Kuczys 2023-06-14 04:56:50 +02:00 committed by GitHub
parent 3abf4cac05
commit 10e09d6abc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 216 additions and 173 deletions

View File

@ -215,11 +215,11 @@ modset deletenames
**Description**
Delete all stored usernames and nicknames.
Delete all stored usernames, global display names, and server nicknames.
**Arguments**
- ``<confirmation>``: Whether to delete all stored usernames and nicknames. |bool-input|
- ``<confirmation>``: Whether to delete all stored usernames, global display names, and server nicknames. |bool-input|
.. _mod-command-modset-deleterepeats:
@ -469,7 +469,7 @@ modset tracknicknames
**Description**
Toggle whether nickname changes should be tracked.
Toggle whether server nickname changes should be tracked.
This setting will be overridden if trackallnames is disabled.
@ -527,7 +527,7 @@ names
**Description**
Show previous names and nicknames of a member.
Show previous usernames, global display names, and server nicknames of a member.
**Arguments**
@ -549,14 +549,14 @@ rename
**Description**
Change a member's nickname.
Change a member's server nickname.
Leaving the nickname empty will remove it.
Leaving the nickname argument empty will remove it.
**Arguments**
* ``<member>``: |member-input|
* ``[nickname]``: The new nickname for the member.
* ``[nickname]``: The new server nickname for the member.
.. _mod-command-slowmode:
@ -684,9 +684,9 @@ userinfo
Show information about a user.
This includes fields for status, discord join date, server
join date, voice state and previous names/nicknames.
join date, voice state and previous usernames/global display names/nicknames.
If the user has no roles, previous names or previous nicknames,
If the user has no roles, previous usernames, global display names, or server nicknames,
these fields will be omitted.
**Arguments**

View File

@ -272,7 +272,9 @@ class Admin(commands.Cog):
`[p]editrole colour Test #ff9900`
"""
author = ctx.author
reason = "{}({}) changed the colour of role '{}'".format(author.name, author.id, role.name)
reason = _("{author} ({author.id}) changed the colour of role '{role.name}'").format(
author=author, role=role.name
)
if not self.pass_user_hierarchy_check(ctx, role):
await ctx.send(_(ROLE_USER_HIERARCHY_ISSUE).format(role=role))
@ -303,9 +305,9 @@ class Admin(commands.Cog):
"""
author = ctx.message.author
old_name = role.name
reason = "{}({}) changed the name of role '{}' to '{}'".format(
author.name, author.id, old_name, name
)
reason = _(
"{author} ({author.id}) changed the name of role '{old_name}' to '{name}'"
).format(author=author, old_name=old_name, name=name)
if not self.pass_user_hierarchy_check(ctx, role):
await ctx.send(_(ROLE_USER_HIERARCHY_ISSUE).format(role=role))

View File

@ -113,7 +113,9 @@ async def global_unique_user_finder(
return user
maybe_matches = []
async for user in AsyncIter(bot.users).filter(lambda u: u.name == arg or f"{u}" == arg):
async for user in AsyncIter(bot.users).filter(
lambda u: u.name == arg or u.global_name == arg or f"{u}" == arg
):
maybe_matches.append(user)
if guild is not None:

View File

@ -105,32 +105,30 @@ class MiscellaneousCommands(MixinMeta, metaclass=CompositeMetaClass):
queue_tracks = player.queue
requesters = {"total": 0, "users": {}}
async def _usercount(req_username):
if req_username in requesters["users"]:
requesters["users"][req_username]["songcount"] += 1
async def _usercount(req_user_handle):
if req_user_handle in requesters["users"]:
requesters["users"][req_user_handle]["songcount"] += 1
requesters["total"] += 1
else:
requesters["users"][req_username] = {}
requesters["users"][req_username]["songcount"] = 1
requesters["users"][req_user_handle] = {}
requesters["users"][req_user_handle]["songcount"] = 1
requesters["total"] += 1
async for track in AsyncIter(queue_tracks):
req_username = "{}#{}".format(track.requester.name, track.requester.discriminator)
await _usercount(req_username)
req_user_handle = str(track.requester)
await _usercount(req_user_handle)
try:
req_username = "{}#{}".format(
player.current.requester.name, player.current.requester.discriminator
)
await _usercount(req_username)
req_user_handle = str(player.current.requester)
await _usercount(req_user_handle)
except AttributeError:
return await self.send_embed_msg(ctx, title=_("There's nothing in the queue."))
async for req_username in AsyncIter(requesters["users"]):
percentage = float(requesters["users"][req_username]["songcount"]) / float(
async for req_user_handle in AsyncIter(requesters["users"]):
percentage = float(requesters["users"][req_user_handle]["songcount"]) / float(
requesters["total"]
)
requesters["users"][req_username]["percent"] = round(percentage * 100, 1)
requesters["users"][req_user_handle]["percent"] = round(percentage * 100, 1)
top_queue_users = heapq.nlargest(
20,

View File

@ -61,7 +61,7 @@ HUMANIZED_PERM = {
"manage_nicknames": _("Manage Nicknames"),
"manage_roles": _("Manage Roles"),
"manage_webhooks": _("Manage Webhooks"),
"manage_emojis": _("Manage Emojis"),
"manage_expressions": _("Manage Expressions"),
"use_application_commands": _("Use Application Commands"),
"request_to_speak": _("Request to Speak"),
"manage_events": _("Manage Events"),
@ -72,6 +72,10 @@ HUMANIZED_PERM = {
"send_messages_in_threads": _("Send Messages in Threads"),
"start_embedded_activities": _("Start Activities"),
"moderate_members": _("Moderate Member"),
"use_soundboard": _("Use Soundboard"),
"create_expressions": _("Create Expressions"),
"use_external_sounds": _("Use External Sounds"),
"send_voice_messages": _("Send Voice Messages"),
}
DANGEROUS_COMMANDS = {

View File

@ -228,8 +228,8 @@ class Cleanup(commands.Cog):
)
to_delete.append(ctx.message)
reason = "{}({}) deleted {} messages containing '{}' in channel #{}.".format(
author.name,
reason = "{} ({}) deleted {} messages containing '{}' in channel #{}.".format(
author,
author.id,
humanize_number(len(to_delete), override_locale="en_us"),
text,
@ -295,10 +295,10 @@ class Cleanup(commands.Cog):
to_delete.append(ctx.message)
reason = (
"{}({}) deleted {} messages"
" made by {}({}) in channel #{}."
"{} ({}) deleted {} messages"
" made by {} ({}) in channel #{}."
"".format(
author.name,
author,
author.id,
humanize_number(len(to_delete), override_locale="en_US"),
member or "???",
@ -353,8 +353,8 @@ class Cleanup(commands.Cog):
channel=channel, number=None, after=after, delete_pinned=delete_pinned
)
reason = "{}({}) deleted {} messages in channel #{}.".format(
author.name,
reason = "{} ({}) deleted {} messages in channel #{}.".format(
author,
author.id,
humanize_number(len(to_delete), override_locale="en_US"),
channel.name,
@ -409,8 +409,8 @@ class Cleanup(commands.Cog):
)
to_delete.append(ctx.message)
reason = "{}({}) deleted {} messages in channel #{}.".format(
author.name,
reason = "{} ({}) deleted {} messages in channel #{}.".format(
author,
author.id,
humanize_number(len(to_delete), override_locale="en_US"),
channel.name,
@ -462,8 +462,8 @@ class Cleanup(commands.Cog):
channel=channel, before=mtwo, after=mone, delete_pinned=delete_pinned
)
to_delete.append(ctx.message)
reason = "{}({}) deleted {} messages in channel #{}.".format(
author.name,
reason = "{} ({}) deleted {} messages in channel #{}.".format(
author,
author.id,
humanize_number(len(to_delete), override_locale="en_US"),
channel.name,
@ -504,8 +504,8 @@ class Cleanup(commands.Cog):
)
to_delete.append(ctx.message)
reason = "{}({}) deleted {} messages in channel #{}.".format(
author.name, author.id, len(to_delete), channel.name
reason = "{} ({}) deleted {} messages in channel #{}.".format(
author, author.id, len(to_delete), channel.name
)
log.info(reason)
@ -585,10 +585,10 @@ class Cleanup(commands.Cog):
to_delete.append(ctx.message)
reason = (
"{}({}) deleted {}"
"{} ({}) deleted {}"
" command messages in channel #{}."
"".format(
author.name,
author,
author.id,
humanize_number(len(to_delete), override_locale="en_US"),
channel.name,
@ -670,15 +670,11 @@ class Cleanup(commands.Cog):
else:
channel_name = str(channel)
reason = (
"{}({}) deleted {} messages "
"sent by the bot in {}."
"".format(
author.name,
author.id,
humanize_number(len(to_delete), override_locale="en_US"),
channel_name,
)
reason = "{} ({}) deleted {} messages sent by the bot in {}.".format(
author,
author.id,
humanize_number(len(to_delete), override_locale="en_US"),
channel_name,
)
log.info(reason)

View File

@ -434,7 +434,9 @@ class Economy(commands.Cog):
if show_global and await bank.is_global():
# show_global is only applicable if bank is global
bank_sorted = await bank.get_leaderboard(positions=top, guild=None)
base_embed.set_author(name=ctx.bot.user.name, icon_url=ctx.bot.user.display_avatar)
base_embed.set_author(
name=ctx.bot.user.display_name, icon_url=ctx.bot.user.display_avatar
)
else:
bank_sorted = await bank.get_leaderboard(positions=top, guild=guild)
if guild:

View File

@ -355,7 +355,7 @@ class General(commands.Cog):
joined_on = _(
"{bot_name} joined this server on {bot_join}. That's over {since_join} days ago!"
).format(
bot_name=ctx.bot.user.name,
bot_name=ctx.bot.user.display_name,
bot_join=guild.me.joined_at.strftime("%d %b %Y %H:%M:%S"),
since_join=humanize_number((ctx.message.created_at - guild.me.joined_at).days),
)

View File

@ -1,6 +1,7 @@
import logging
from datetime import timezone
from collections import defaultdict, deque
from typing import List, Optional
import discord
from redbot.core import i18n, modlog, commands
@ -158,6 +159,17 @@ class Events(MixinMeta):
if not deleted:
await self.check_mention_spam(message)
@staticmethod
def _update_past_names(name: str, name_list: List[Optional[str]]) -> None:
while None in name_list: # clean out null entries from a bug
name_list.remove(None)
if name in name_list:
# Ensure order is maintained without duplicates occurring
name_list.remove(name)
name_list.append(name)
while len(name_list) > 20:
name_list.pop(0)
@commands.Cog.listener()
async def on_user_update(self, before: discord.User, after: discord.User):
if before.name != after.name:
@ -165,14 +177,13 @@ class Events(MixinMeta):
if not track_all_names:
return
async with self.config.user(before).past_names() as name_list:
while None in name_list: # clean out null entries from a bug
name_list.remove(None)
if before.name in name_list:
# Ensure order is maintained without duplicates occurring
name_list.remove(before.name)
name_list.append(before.name)
while len(name_list) > 20:
name_list.pop(0)
self._update_past_names(before.name, name_list)
if before.display_name != after.display_name:
track_all_names = await self.config.track_all_names()
if not track_all_names:
return
async with self.config.user(before).past_display_names() as name_list:
self._update_past_names(before.display_name, name_list)
@commands.Cog.listener()
async def on_member_update(self, before: discord.Member, after: discord.Member):
@ -185,10 +196,4 @@ class Events(MixinMeta):
if (not track_all_names) or (not track_nicknames):
return
async with self.config.member(before).past_nicks() as nick_list:
while None in nick_list: # clean out null entries from a bug
nick_list.remove(None)
if before.nick in nick_list:
nick_list.remove(before.nick)
nick_list.append(before.nick)
while len(nick_list) > 20:
nick_list.pop(0)
self._update_past_names(before.nick, nick_list)

View File

@ -177,21 +177,23 @@ class KickBanMixin(MixinMeta):
if removed_temp:
log.info(
"{}({}) upgraded the tempban for {} to a permaban.".format(
author.name, author.id, user.id
)
"%s (%s) upgraded the tempban for %s to a permaban.", author, author.id, user.id
)
success_message = _(
"User with ID {user_id} was upgraded from a temporary to a permanent ban."
).format(user_id=user.id)
else:
username = user.name if hasattr(user, "name") else "Unknown"
user_handle = str(user) if isinstance(user, discord.abc.User) else "Unknown"
try:
await guild.ban(user, reason=audit_reason, delete_message_seconds=days * 86400)
log.info(
"{}({}) {}ned {}({}), deleting {} days worth of messages.".format(
author.name, author.id, ban_type, username, user.id, str(days)
)
"%s (%s) %sned %s (%s), deleting %s days worth of messages.",
author,
author.id,
ban_type,
user_handle,
user.id,
days,
)
success_message = _("Done. That felt good.")
except discord.Forbidden:
@ -200,9 +202,12 @@ class KickBanMixin(MixinMeta):
return False, _("User with ID {user_id} not found").format(user_id=user.id)
except Exception:
log.exception(
"{}({}) attempted to {} {}({}), but an error occurred.".format(
author.name, author.id, ban_type, username, user.id
)
"%s (%s) attempted to %s %s (%s), but an error occurred.",
author,
author.id,
ban_type,
user_handle,
user.id,
)
return False, _("An unexpected error occurred.")
@ -333,14 +338,16 @@ class KickBanMixin(MixinMeta):
await member.send(embed=em)
try:
await guild.kick(member, reason=audit_reason)
log.info("{}({}) kicked {}({})".format(author.name, author.id, member.name, member.id))
log.info("%s (%s) kicked %s (%s)", author, author.id, member, member.id)
except discord.errors.Forbidden:
await ctx.send(_("I'm not allowed to do that."))
except Exception:
log.exception(
"{}({}) attempted to kick {}({}), but an error occurred.".format(
author.name, author.id, member.name, member.id
)
"%s (%s) attempted to kick %s (%s), but an error occurred.",
author,
author.id,
member,
member.id,
)
else:
await modlog.create_case(
@ -531,9 +538,10 @@ class KickBanMixin(MixinMeta):
tempbans.remove(user_id)
upgrades.append(str(user_id))
log.info(
"{}({}) upgraded the tempban for {} to a permaban.".format(
author.name, author.id, user_id
)
"%s (%s) upgraded the tempban for %s to a permaban.",
author,
author.id,
user_id,
)
banned.append(user_id)
else:
@ -541,7 +549,7 @@ class KickBanMixin(MixinMeta):
await guild.ban(
user, reason=audit_reason, delete_message_seconds=days * 86400
)
log.info("{}({}) hackbanned {}".format(author.name, author.id, user_id))
log.info("%s (%s) hackbanned %s", author, author.id, user_id)
except discord.NotFound:
errors[user_id] = _("User with ID {user_id} not found").format(
user_id=user_id
@ -716,24 +724,32 @@ class KickBanMixin(MixinMeta):
return
except discord.HTTPException:
log.exception(
"{}({}) attempted to softban {}({}), but an error occurred trying to ban them.".format(
author.name, author.id, member.name, member.id
)
"%s (%s) attempted to softban %s (%s), but an error occurred trying to ban them.",
author,
author.id,
member,
member.id,
)
return
try:
await guild.unban(member)
except discord.HTTPException:
log.exception(
"{}({}) attempted to softban {}({}), but an error occurred trying to unban them.".format(
author.name, author.id, member.name, member.id
)
"%s (%s) attempted to softban %s (%s),"
" but an error occurred trying to unban them.",
author,
author.id,
member,
member.id,
)
return
else:
log.info(
"{}({}) softbanned {}({}), deleting 1 day worth "
"of messages.".format(author.name, author.id, member.name, member.id)
"%s (%s) softbanned %s (%s), deleting 1 day worth of messages.",
author,
author.id,
member,
member.id,
)
await modlog.create_case(
self.bot,

View File

@ -66,7 +66,7 @@ class Mod(
default_member_settings = {"past_nicks": [], "perms_cache": {}, "banned_until": False}
default_user_settings = {"past_names": []}
default_user_settings = {"past_names": [], "past_display_names": []}
def __init__(self, bot: Red):
super().__init__()

View File

@ -1,8 +1,9 @@
import datetime
from typing import cast
from typing import List, Tuple, cast
import discord
from redbot.core import commands, i18n
from redbot.core.utils.chat_formatting import bold, pagify
from redbot.core.utils.common_filters import (
filter_invites,
filter_various_mentions,
@ -20,23 +21,23 @@ class ModInfo(MixinMeta):
Commands regarding names, userinfo, etc.
"""
async def get_names_and_nicks(self, user):
names = await self.config.user(user).past_names()
nicks = await self.config.member(user).past_nicks()
if names:
names = [escape_spoilers_and_mass_mentions(name) for name in names if name]
if nicks:
nicks = [escape_spoilers_and_mass_mentions(nick) for nick in nicks if nick]
return names, nicks
async def get_names(self, member: discord.Member) -> Tuple[List[str], List[str], List[str]]:
user_data = await self.config.user(member).all()
usernames, display_names = user_data["past_names"], user_data["past_display_names"]
nicks = await self.config.member(member).past_nicks()
usernames = list(map(escape_spoilers_and_mass_mentions, filter(None, usernames)))
display_names = list(map(escape_spoilers_and_mass_mentions, filter(None, display_names)))
nicks = list(map(escape_spoilers_and_mass_mentions, filter(None, nicks)))
return usernames, display_names, nicks
@commands.command()
@commands.guild_only()
@commands.bot_has_permissions(manage_nicknames=True)
@commands.admin_or_permissions(manage_nicknames=True)
async def rename(self, ctx: commands.Context, member: discord.Member, *, nickname: str = ""):
"""Change a member's nickname.
"""Change a member's server nickname.
Leaving the nickname empty will remove it.
Leaving the nickname argument empty will remove it.
"""
nickname = nickname.strip()
me = cast(discord.Member, ctx.me)
@ -175,9 +176,9 @@ class ModInfo(MixinMeta):
"""Show information about a member.
This includes fields for status, discord join date, server
join date, voice state and previous names/nicknames.
join date, voice state and previous usernames/global display names/nicknames.
If the member has no roles, previous names or previous nicknames,
If the member has no roles, previous usernames, global display names, or server nicknames,
these fields will be omitted.
"""
author = ctx.author
@ -191,7 +192,7 @@ class ModInfo(MixinMeta):
is_special = member.id == 96130341705637888 and guild.id == 133049272517001216
roles = member.roles[-1:0:-1]
names, nicks = await self.get_names_and_nicks(member)
usernames, display_names, nicks = await self.get_names(member)
if is_special:
joined_at = special_date
@ -273,22 +274,17 @@ class ModInfo(MixinMeta):
data.add_field(
name=_("Roles") if len(roles) > 1 else _("Role"), value=role_str, inline=False
)
if names:
# May need sanitizing later, but mentions do not ping in embeds currently
val = filter_invites(", ".join(names))
data.add_field(
name=_("Previous Names") if len(names) > 1 else _("Previous Name"),
value=val,
inline=False,
)
if nicks:
# May need sanitizing later, but mentions do not ping in embeds currently
val = filter_invites(", ".join(nicks))
data.add_field(
name=_("Previous Nicknames") if len(nicks) > 1 else _("Previous Nickname"),
value=val,
inline=False,
)
for single_form, plural_form, names in (
(_("Previous Username"), _("Previous Usernames"), usernames),
(_("Previous Global Display Name"), _("Previous Global Display Names"), display_names),
(_("Previous Server Nickname"), _("Previous Server Nicknames"), nicks),
):
if names:
data.add_field(
name=plural_form if len(names) > 1 else single_form,
value=filter_invites(", ".join(names)),
inline=False,
)
if voice_state and voice_state.channel:
data.add_field(
name=_("Current voice channel"),
@ -309,21 +305,20 @@ class ModInfo(MixinMeta):
@commands.command()
async def names(self, ctx: commands.Context, *, member: discord.Member):
"""Show previous names and nicknames of a member."""
names, nicks = await self.get_names_and_nicks(member)
msg = ""
if names:
msg += _("**Past 20 names**:")
msg += "\n"
msg += ", ".join(names)
if nicks:
if msg:
msg += "\n\n"
msg += _("**Past 20 nicknames**:")
msg += "\n"
msg += ", ".join(nicks)
if msg:
msg = filter_various_mentions(msg)
await ctx.send(msg)
"""Show previous usernames, global display names, and server nicknames of a member."""
usernames, display_names, nicks = await self.get_names(member)
parts = []
for header, names in (
(_("Past 20 usernames:"), usernames),
(_("Past 20 global display names:"), display_names),
(_("Past 20 server nicknames:"), nicks),
):
if names:
parts.append(bold(header) + ", ".join(names))
if parts:
# each name can have 32 characters, we store 3*20 names which totals to
# 60*32=1920 characters which is quite close to the message length limit
for msg in pagify(filter_various_mentions("\n\n".join(parts))):
await ctx.send(msg)
else:
await ctx.send(_("That member doesn't have any recorded name or nickname change."))

View File

@ -418,7 +418,7 @@ class ModSettings(MixinMeta):
@commands.guild_only()
async def tracknicknames(self, ctx: commands.Context, enabled: bool = None):
"""
Toggle whether nickname changes should be tracked.
Toggle whether server nickname changes should be tracked.
This setting will be overridden if trackallnames is disabled.
"""
@ -470,11 +470,11 @@ class ModSettings(MixinMeta):
@commands.max_concurrency(1, commands.BucketType.default)
@commands.is_owner()
async def deletenames(self, ctx: commands.Context, confirmation: bool = False) -> None:
"""Delete all stored usernames and nicknames.
"""Delete all stored usernames, global display names, and server nicknames.
Examples:
- `[p]modset deletenames` - Did not confirm. Shows the help message.
- `[p]modset deletenames yes` - Deletes all stored usernames and nicknames.
- `[p]modset deletenames yes` - Deletes all stored usernames, global display names, and server nicknames.
**Arguments**
@ -483,8 +483,8 @@ class ModSettings(MixinMeta):
if not confirmation:
await ctx.send(
_(
"This will delete all stored usernames and nicknames the bot has stored."
"\nIf you're sure, type {command}"
"This will delete all stored usernames, global display names,"
" and server nicknames the bot has stored.\nIf you're sure, type {command}"
).format(command=inline(f"{ctx.clean_prefix}modset deletenames yes"))
)
return
@ -511,16 +511,23 @@ class ModSettings(MixinMeta):
async for guild_id in AsyncIter(guilds_to_remove, steps=100):
del mod_member_data[guild_id]
# Username data
# Username and global display name data
async with self.config._get_base_group(self.config.USER).all() as mod_user_data:
users_to_remove = []
async for user_id, user_data in AsyncIter(mod_user_data.items(), steps=100):
if "past_names" in user_data:
del user_data["past_names"]
if "past_display_names" in user_data:
del user_data["past_display_names"]
if not user_data:
users_to_remove.append(user_id)
async for user_id in AsyncIter(users_to_remove, steps=100):
del mod_user_data[user_id]
await ctx.send(_("Usernames and nicknames have been deleted from Mod config."))
await ctx.send(
_(
"Usernames, global display names, and server nicknames"
" have been deleted from Mod config."
)
)

View File

@ -323,7 +323,7 @@ class TriviaSession:
if payout <= 0:
return
for winner in winners:
LOG.debug("Paying trivia winner: %d credits --> %s", payout, winner.name)
LOG.debug("Paying trivia winner: %d credits --> %s", payout, winner)
try:
await bank.deposit_credits(winner, payout)
except errors.BalanceTooHigh as e:

View File

@ -183,13 +183,13 @@ def init_events(bot, cli_flags):
if guilds:
rich_console.print(
Columns(
[Panel(table_general_info, title=str(bot.user.name)), Panel(table_counts)],
[Panel(table_general_info, title=bot.user.display_name), Panel(table_counts)],
equal=True,
align="center",
)
)
else:
rich_console.print(Columns([Panel(table_general_info, title=str(bot.user.name))]))
rich_console.print(Columns([Panel(table_general_info, title=bot.user.display_name)]))
rich_console.print(
"Loaded {} cogs with {} commands".format(len(bot.cogs), len(bot.commands))

View File

@ -1794,6 +1794,8 @@ class Red(
Checks if the user, message, context, or role should be considered immune from automated
moderation actions.
Bot users are considered immune.
This will return ``False`` in direct messages.
Parameters
@ -1812,22 +1814,22 @@ class Red(
return False
if isinstance(to_check, discord.Role):
ids_to_check = [to_check.id]
ids_to_check = {to_check.id}
else:
author = getattr(to_check, "author", to_check)
if author.bot:
return True
ids_to_check = set()
try:
ids_to_check = [r.id for r in author.roles]
ids_to_check = {r.id for r in author.roles}
except AttributeError:
# webhook messages are a user not member,
# cheaper than isinstance
if author.bot and author.discriminator == "0000":
return True # webhooks require significant permissions to enable.
else:
ids_to_check.append(author.id)
# cheaper than isinstance(author, discord.User)
pass
ids_to_check.add(author.id)
immune_ids = await self._config.guild(guild).autoimmune_ids()
return any(i in immune_ids for i in ids_to_check)
return not ids_to_check.isdisjoint(immune_ids)
@staticmethod
async def send_filtered(

View File

@ -2568,7 +2568,9 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
"This will delete all bank accounts for {scope}.\nIf you're sure, type "
"`{prefix}bankset reset yes`"
).format(
scope=self.bot.user.name if await bank.is_global() else _("this server"),
scope=self.bot.user.display_name
if await bank.is_global()
else _("this server"),
prefix=ctx.clean_prefix,
)
)
@ -2576,7 +2578,9 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
await bank.wipe_bank(guild=ctx.guild)
await ctx.send(
_("All bank accounts for {scope} have been deleted.").format(
scope=self.bot.user.name if await bank.is_global() else _("this server")
scope=self.bot.user.display_name
if await bank.is_global()
else _("this server")
)
)
@ -3855,7 +3859,7 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
"Global regional format: {regional_format}\n"
"Default embed colour: {colour}"
).format(
bot_name=ctx.bot.user.name,
bot_name=ctx.bot.user.display_name,
prefixes=prefix_string,
guild_settings=guild_settings,
locale=locale,

View File

@ -306,8 +306,8 @@ class Case:
(note: it might not exist regardless of whether this attribute is `None`)
or if it has never been created.
last_known_username: Optional[str]
The last known username of the user.
`None` if the username of the user was never saved
The last known user handle (``username`` / ``username#1234``) of the user.
`None` if the handle of the user was never saved
or if their data had to be anonymized.
"""
@ -393,9 +393,9 @@ class Case:
else:
setattr(self, item, value)
# update last known username
# update last known user handle
if not isinstance(self.user, int):
self.last_known_username = f"{self.user.name}#{self.user.discriminator}"
self.last_known_username = str(self.user)
if isinstance(self.channel, discord.Thread):
self.parent_channel_id = self.channel.parent_id
@ -503,7 +503,15 @@ class Case:
# can't use _() inside f-string expressions, see bpo-36310 and red#3818
translated = _("Unknown or Deleted User")
user = f"[{translated}] ({self.user})"
# Handle pomelo usernames stored before we updated our implementation
elif self.last_known_username.endswith("#0"):
user = f"{self.last_known_username[:-2]} ({self.user})"
# New usernames can't contain `#` and old usernames couldn't either.
elif len(self.last_known_username) <= 5 or self.last_known_username[-5] != "#":
user = f"{self.last_known_username} ({self.user})"
# Last known user handle is a legacy username with a discriminator
else:
# isolate the name so that the direction of the discriminator and ID aren't changed
# See usage explanation here: https://www.unicode.org/reports/tr9/#Formatting
name = self.last_known_username[:-5]
discriminator = self.last_known_username[-4:]
@ -511,8 +519,10 @@ class Case:
f"\N{FIRST STRONG ISOLATE}{name}"
f"\N{POP DIRECTIONAL ISOLATE}#{discriminator} ({self.user})"
)
elif self.user.discriminator == "0":
user = f"{self.user} ({self.user.id})"
else:
# isolate the name so that the direction of the discriminator and ID do not get changed
# isolate the name so that the direction of the discriminator and ID aren't changed
# See usage explanation here: https://www.unicode.org/reports/tr9/#Formatting
user = escape_spoilers(
filter_invites(
@ -1019,7 +1029,7 @@ async def create_case(
channel: Optional[Union[discord.abc.GuildChannel, discord.Thread]]
The channel the action was taken in
last_known_username: Optional[str]
The last known username of the user
The last known user handle (``username`` / ``username#1234``) of the user
Note: This is ignored if a Member or User object is provided
in the user field

View File

@ -162,7 +162,7 @@ class Tunnel(metaclass=TunnelMeta):
"""
files = []
max_size = 8 * 1000 * 1000
max_size = 26214400
if m.attachments and sum(a.size for a in m.attachments) <= max_size:
for a in m.attachments:
if images_only and a.height is None:

View File

@ -28,7 +28,7 @@ click==8.1.3
# via -r base.in
contextlib2==21.6.0
# via schema
discord-py==2.2.3
discord-py==2.3.0
# via
# -r base.in
# red-lavalink