mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
[Mutes] Add ability to send DMs on mute/unmute (#4563)
* handle manual mutes/unmutes Doing this in the Web-Editor is painful. Let's switch to VSC. * embed version * non embed * config stuff * testing done * wow black * Few things before I start local testing * Fix new lines * Make messages not depend on modlog * Yay voicemutes * black+import * what is your ducking problem vscode * adress review * this is driving me mad * Check the config in `_send_dm_notification` to avoid code repetition * Fix incorrect type hints * Remove no longer needed line changes * Remove unused function * Update the type hints from commit 946299 in the MixinMeta too * Fixed wrong variable being passed to the method and ensure DMs aren't sent when we couldn't get the member object * They call me dumb for a reason * Stop overriding variable with duration + various formatting tweaks * :( * We need to differ between voice and text in two places, interesting... * Show info about no reason provided in embed * Apparently, the `reason` can also be an empty string :| * Update redbot/cogs/mutes/mutes.py Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com> Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>
This commit is contained in:
parent
2ce4a275fc
commit
aa0ee3385d
@ -1,5 +1,5 @@
|
|||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import List, Tuple, Optional, Dict
|
from typing import List, Tuple, Optional, Dict, Union
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
@ -25,3 +25,15 @@ class MixinMeta(ABC):
|
|||||||
ctx: commands.Context, user_voice_state: Optional[discord.VoiceState], **perms: bool
|
ctx: commands.Context, user_voice_state: Optional[discord.VoiceState], **perms: bool
|
||||||
) -> bool:
|
) -> bool:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def _send_dm_notification(
|
||||||
|
self,
|
||||||
|
user: Union[discord.User, discord.Member],
|
||||||
|
moderator: Optional[Union[discord.User, discord.Member]],
|
||||||
|
guild: discord.Guild,
|
||||||
|
mute_type: str,
|
||||||
|
reason: Optional[str],
|
||||||
|
duration=None,
|
||||||
|
):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|||||||
@ -13,7 +13,7 @@ from .voicemutes import VoiceMutes
|
|||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
from redbot.core import commands, checks, i18n, modlog, Config
|
from redbot.core import commands, checks, i18n, modlog, Config
|
||||||
from redbot.core.utils import bounded_gather
|
from redbot.core.utils import bounded_gather
|
||||||
from redbot.core.utils.chat_formatting import humanize_timedelta, humanize_list, pagify
|
from redbot.core.utils.chat_formatting import bold, humanize_timedelta, humanize_list, pagify
|
||||||
from redbot.core.utils.mod import get_audit_reason
|
from redbot.core.utils.mod import get_audit_reason
|
||||||
from redbot.core.utils.menus import start_adding_reactions
|
from redbot.core.utils.menus import start_adding_reactions
|
||||||
from redbot.core.utils.predicates import MessagePredicate, ReactionPredicate
|
from redbot.core.utils.predicates import MessagePredicate, ReactionPredicate
|
||||||
@ -77,6 +77,8 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
"notification_channel": None,
|
"notification_channel": None,
|
||||||
"muted_users": {},
|
"muted_users": {},
|
||||||
"default_time": 0,
|
"default_time": 0,
|
||||||
|
"dm": False,
|
||||||
|
"show_mod": False,
|
||||||
}
|
}
|
||||||
self.config.register_global(force_role_mutes=True)
|
self.config.register_global(force_role_mutes=True)
|
||||||
# Tbh I would rather force everyone to use role mutes.
|
# Tbh I would rather force everyone to use role mutes.
|
||||||
@ -256,6 +258,9 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
_("Automatic unmute"),
|
_("Automatic unmute"),
|
||||||
until=None,
|
until=None,
|
||||||
)
|
)
|
||||||
|
await self._send_dm_notification(
|
||||||
|
member, author, guild, _("Server unmute"), _("Automatic unmute")
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
chan_id = await self.config.guild(guild).notification_channel()
|
chan_id = await self.config.guild(guild).notification_channel()
|
||||||
notification_channel = guild.get_channel(chan_id)
|
notification_channel = guild.get_channel(chan_id)
|
||||||
@ -363,6 +368,9 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
modlog_reason,
|
modlog_reason,
|
||||||
until=None,
|
until=None,
|
||||||
)
|
)
|
||||||
|
await self._send_dm_notification(
|
||||||
|
member, author, guild, _("Server unmute"), _("Automatic unmute")
|
||||||
|
)
|
||||||
self._channel_mute_events[guild.id].set()
|
self._channel_mute_events[guild.id].set()
|
||||||
if any(results):
|
if any(results):
|
||||||
reasons = {}
|
reasons = {}
|
||||||
@ -424,8 +432,10 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
if create_case:
|
if create_case:
|
||||||
if isinstance(channel, discord.VoiceChannel):
|
if isinstance(channel, discord.VoiceChannel):
|
||||||
unmute_type = "vunmute"
|
unmute_type = "vunmute"
|
||||||
|
notification_title = _("Voice unmute")
|
||||||
else:
|
else:
|
||||||
unmute_type = "cunmute"
|
unmute_type = "cunmute"
|
||||||
|
notification_title = _("Channel unmute")
|
||||||
await modlog.create_case(
|
await modlog.create_case(
|
||||||
self.bot,
|
self.bot,
|
||||||
channel.guild,
|
channel.guild,
|
||||||
@ -437,6 +447,9 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
until=None,
|
until=None,
|
||||||
channel=channel,
|
channel=channel,
|
||||||
)
|
)
|
||||||
|
await self._send_dm_notification(
|
||||||
|
member, author, channel.guild, notification_title, _("Automatic unmute")
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
error_msg = _(
|
error_msg = _(
|
||||||
@ -457,6 +470,72 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
else:
|
else:
|
||||||
return (member, channel, success["reason"])
|
return (member, channel, success["reason"])
|
||||||
|
|
||||||
|
async def _send_dm_notification(
|
||||||
|
self,
|
||||||
|
user: Union[discord.User, discord.Member],
|
||||||
|
moderator: Optional[Union[discord.User, discord.Member]],
|
||||||
|
guild: discord.Guild,
|
||||||
|
mute_type: str,
|
||||||
|
reason: Optional[str],
|
||||||
|
duration=None,
|
||||||
|
):
|
||||||
|
if not await self.config.guild(guild).dm():
|
||||||
|
return
|
||||||
|
|
||||||
|
show_mod = await self.config.guild(guild).show_mod()
|
||||||
|
title = bold(mute_type)
|
||||||
|
if duration:
|
||||||
|
duration_str = humanize_timedelta(timedelta=duration)
|
||||||
|
until = datetime.now(timezone.utc) + duration
|
||||||
|
until_str = until.strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||||
|
|
||||||
|
if moderator is None:
|
||||||
|
moderator_str = _("Unknown")
|
||||||
|
else:
|
||||||
|
moderator_str = str(moderator)
|
||||||
|
|
||||||
|
if not reason:
|
||||||
|
reason = _("No reason provided.")
|
||||||
|
|
||||||
|
# okay, this is some poor API to require PrivateChannel here...
|
||||||
|
if await self.bot.embed_requested(await user.create_dm(), user):
|
||||||
|
em = discord.Embed(
|
||||||
|
title=title,
|
||||||
|
description=reason,
|
||||||
|
color=await self.bot.get_embed_color(user),
|
||||||
|
)
|
||||||
|
em.timestamp = datetime.utcnow()
|
||||||
|
if duration:
|
||||||
|
em.add_field(name=_("Until"), value=until_str)
|
||||||
|
em.add_field(name=_("Duration"), value=duration_str)
|
||||||
|
em.add_field(name=_("Guild"), value=guild.name, inline=False)
|
||||||
|
if show_mod:
|
||||||
|
em.add_field(name=_("Moderator"), value=moderator_str)
|
||||||
|
try:
|
||||||
|
await user.send(embed=em)
|
||||||
|
except discord.Forbidden:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
message = f"{title}\n>>> "
|
||||||
|
message += reason
|
||||||
|
message += (
|
||||||
|
_("\n**Moderator**: {moderator}").format(moderator=moderator_str)
|
||||||
|
if show_mod
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
message += (
|
||||||
|
_("\n**Until**: {until}\n**Duration**: {duration}").format(
|
||||||
|
until=until_str, duration=duration_str
|
||||||
|
)
|
||||||
|
if duration
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
message += _("\n**Guild**: {guild_name}").format(guild_name=guild.name)
|
||||||
|
try:
|
||||||
|
await user.send(message)
|
||||||
|
except discord.Forbidden:
|
||||||
|
pass
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_member_update(self, before: discord.Member, after: discord.Member):
|
async def on_member_update(self, before: discord.Member, after: discord.Member):
|
||||||
"""
|
"""
|
||||||
@ -494,6 +573,9 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
)
|
)
|
||||||
del self._server_mutes[guild.id][after.id]
|
del self._server_mutes[guild.id][after.id]
|
||||||
should_save = True
|
should_save = True
|
||||||
|
await self._send_dm_notification(
|
||||||
|
after, None, guild, _("Server unmute"), _("Manually removed mute role")
|
||||||
|
)
|
||||||
elif mute_role in roles_added:
|
elif mute_role in roles_added:
|
||||||
# send modlog case for mute and add to cache
|
# send modlog case for mute and add to cache
|
||||||
if guild.id not in self._server_mutes:
|
if guild.id not in self._server_mutes:
|
||||||
@ -515,6 +597,9 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
"until": None,
|
"until": None,
|
||||||
}
|
}
|
||||||
should_save = True
|
should_save = True
|
||||||
|
await self._send_dm_notification(
|
||||||
|
after, None, guild, _("Server mute"), _("Manually applied mute role")
|
||||||
|
)
|
||||||
if should_save:
|
if should_save:
|
||||||
await self.config.guild(guild).muted_users.set(self._server_mutes[guild.id])
|
await self.config.guild(guild).muted_users.set(self._server_mutes[guild.id])
|
||||||
|
|
||||||
@ -555,15 +640,27 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
user_id not in after_perms or any((send_messages, speak))
|
user_id not in after_perms or any((send_messages, speak))
|
||||||
):
|
):
|
||||||
user = after.guild.get_member(user_id)
|
user = after.guild.get_member(user_id)
|
||||||
|
send_dm_notification = True
|
||||||
if not user:
|
if not user:
|
||||||
|
send_dm_notification = False
|
||||||
user = discord.Object(id=user_id)
|
user = discord.Object(id=user_id)
|
||||||
log.debug(f"{user} - {type(user)}")
|
log.debug(f"{user} - {type(user)}")
|
||||||
to_del.append(user_id)
|
to_del.append(user_id)
|
||||||
log.debug("creating case")
|
log.debug("creating case")
|
||||||
if isinstance(after, discord.VoiceChannel):
|
if isinstance(after, discord.VoiceChannel):
|
||||||
unmute_type = "vunmute"
|
unmute_type = "vunmute"
|
||||||
|
notification_title = _("Voice unmute")
|
||||||
else:
|
else:
|
||||||
unmute_type = "cunmute"
|
unmute_type = "cunmute"
|
||||||
|
notification_title = _("Channel unmute")
|
||||||
|
if send_dm_notification:
|
||||||
|
await self._send_dm_notification(
|
||||||
|
user,
|
||||||
|
None,
|
||||||
|
after.guild,
|
||||||
|
notification_title,
|
||||||
|
_("Manually removed channel overwrites"),
|
||||||
|
)
|
||||||
await modlog.create_case(
|
await modlog.create_case(
|
||||||
self.bot,
|
self.bot,
|
||||||
after.guild,
|
after.guild,
|
||||||
@ -614,6 +711,34 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
"""Mute settings."""
|
"""Mute settings."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@muteset.command()
|
||||||
|
@commands.guild_only()
|
||||||
|
async def senddm(self, ctx: commands.Context, true_or_false: bool):
|
||||||
|
"""Set whether mute notifications should be sent to users in DMs."""
|
||||||
|
await self.config.guild(ctx.guild).dm.set(true_or_false)
|
||||||
|
if true_or_false:
|
||||||
|
await ctx.send(_("I will now try to send mute notifications to users DMs."))
|
||||||
|
else:
|
||||||
|
await ctx.send(_("Mute notifications will no longer be sent to users DMs."))
|
||||||
|
|
||||||
|
@muteset.command()
|
||||||
|
@commands.guild_only()
|
||||||
|
async def showmoderator(self, ctx, true_or_false: bool):
|
||||||
|
"""Decide whether the name of the moderator muting a user should be included in the DM to that user."""
|
||||||
|
await self.config.guild(ctx.guild).show_mod.set(true_or_false)
|
||||||
|
if true_or_false:
|
||||||
|
await ctx.send(
|
||||||
|
_(
|
||||||
|
"I will include the name of the moderator who issued the mute when sending a DM to a user."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await ctx.send(
|
||||||
|
_(
|
||||||
|
"I will not include the name of the moderator who issued the mute when sending a DM to a user."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@muteset.command(name="forcerole")
|
@muteset.command(name="forcerole")
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def force_role_mutes(self, ctx: commands.Context, force_role_mutes: bool):
|
async def force_role_mutes(self, ctx: commands.Context, force_role_mutes: bool):
|
||||||
@ -638,11 +763,17 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
notification_channel = ctx.guild.get_channel(data["notification_channel"])
|
notification_channel = ctx.guild.get_channel(data["notification_channel"])
|
||||||
default_time = timedelta(seconds=data["default_time"])
|
default_time = timedelta(seconds=data["default_time"])
|
||||||
msg = _(
|
msg = _(
|
||||||
"Mute Role: {role}\nNotification Channel: {channel}\n" "Default Time: {time}"
|
"Mute Role: {role}\n"
|
||||||
|
"Notification Channel: {channel}\n"
|
||||||
|
"Default Time: {time}\n"
|
||||||
|
"Send DM: {dm}\n"
|
||||||
|
"Show moderator: {show_mod}"
|
||||||
).format(
|
).format(
|
||||||
role=mute_role.mention if mute_role else _("None"),
|
role=mute_role.mention if mute_role else _("None"),
|
||||||
channel=notification_channel.mention if notification_channel else _("None"),
|
channel=notification_channel.mention if notification_channel else _("None"),
|
||||||
time=humanize_timedelta(timedelta=default_time) if default_time else _("None"),
|
time=humanize_timedelta(timedelta=default_time) if default_time else _("None"),
|
||||||
|
dm=data["dm"],
|
||||||
|
show_mod=data["show_mod"],
|
||||||
)
|
)
|
||||||
await ctx.maybe_send_embed(msg)
|
await ctx.maybe_send_embed(msg)
|
||||||
|
|
||||||
@ -1007,6 +1138,9 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
until=until,
|
until=until,
|
||||||
channel=None,
|
channel=None,
|
||||||
)
|
)
|
||||||
|
await self._send_dm_notification(
|
||||||
|
user, author, guild, _("Server mute"), reason, duration
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
issue_list.append(success)
|
issue_list.append(success)
|
||||||
if success_list:
|
if success_list:
|
||||||
@ -1151,6 +1285,9 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
until=until,
|
until=until,
|
||||||
channel=channel,
|
channel=channel,
|
||||||
)
|
)
|
||||||
|
await self._send_dm_notification(
|
||||||
|
user, author, guild, _("Channel mute"), reason, duration
|
||||||
|
)
|
||||||
async with self.config.member(user).perms_cache() as cache:
|
async with self.config.member(user).perms_cache() as cache:
|
||||||
cache[channel.id] = success["old_overs"]
|
cache[channel.id] = success["old_overs"]
|
||||||
else:
|
else:
|
||||||
@ -1217,6 +1354,9 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
reason,
|
reason,
|
||||||
until=None,
|
until=None,
|
||||||
)
|
)
|
||||||
|
await self._send_dm_notification(
|
||||||
|
user, author, guild, _("Server unmute"), reason
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
issue_list.append(success)
|
issue_list.append(success)
|
||||||
self._channel_mute_events[guild.id].set()
|
self._channel_mute_events[guild.id].set()
|
||||||
@ -1281,6 +1421,9 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
|
|||||||
until=None,
|
until=None,
|
||||||
channel=channel,
|
channel=channel,
|
||||||
)
|
)
|
||||||
|
await self._send_dm_notification(
|
||||||
|
user, author, guild, _("Channel unmute"), reason
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
issue_list.append((user, success["reason"]))
|
issue_list.append((user, success["reason"]))
|
||||||
if success_list:
|
if success_list:
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple, Union
|
||||||
from datetime import timezone, timedelta, datetime
|
from datetime import timezone, timedelta, datetime
|
||||||
from .abc import MixinMeta
|
from .abc import MixinMeta
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from redbot.core import commands, checks, i18n, modlog
|
from redbot.core import commands, checks, i18n, modlog
|
||||||
from redbot.core.utils.chat_formatting import (
|
from redbot.core.utils.chat_formatting import (
|
||||||
|
bold,
|
||||||
humanize_timedelta,
|
humanize_timedelta,
|
||||||
humanize_list,
|
humanize_list,
|
||||||
pagify,
|
pagify,
|
||||||
@ -143,6 +144,9 @@ class VoiceMutes(MixinMeta):
|
|||||||
until=until,
|
until=until,
|
||||||
channel=channel,
|
channel=channel,
|
||||||
)
|
)
|
||||||
|
await self._send_dm_notification(
|
||||||
|
user, author, guild, _("Voice mute"), reason, duration
|
||||||
|
)
|
||||||
async with self.config.member(user).perms_cache() as cache:
|
async with self.config.member(user).perms_cache() as cache:
|
||||||
cache[channel.id] = success["old_overs"]
|
cache[channel.id] = success["old_overs"]
|
||||||
else:
|
else:
|
||||||
@ -216,6 +220,9 @@ class VoiceMutes(MixinMeta):
|
|||||||
until=None,
|
until=None,
|
||||||
channel=channel,
|
channel=channel,
|
||||||
)
|
)
|
||||||
|
await self._send_dm_notification(
|
||||||
|
user, author, guild, _("Voice unmute"), reason
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
issue_list.append((user, success["reason"]))
|
issue_list.append((user, success["reason"]))
|
||||||
if success_list:
|
if success_list:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user