aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Leon Sandøy <[email protected]>2019-10-11 21:37:32 +0200
committerGravatar GitHub <[email protected]>2019-10-11 21:37:32 +0200
commitd5f20ca11eb7873a79ff70efbc7db4f4c9fdab23 (patch)
treef3d453eed5c81bdd0ae773493dbac6774bdbfd2c
parentMerge pull request #512 from python-discord/user-left-log (diff)
parentMerge branch 'master' into moderation-tweaks (diff)
Merge pull request #509 from python-discord/moderation-tweaks
Moderation tweaks
-rw-r--r--bot/cogs/moderation/infractions.py56
-rw-r--r--bot/cogs/moderation/management.py17
-rw-r--r--bot/cogs/moderation/superstarify.py22
-rw-r--r--bot/cogs/moderation/utils.py2
4 files changed, 71 insertions, 26 deletions
diff --git a/bot/cogs/moderation/infractions.py b/bot/cogs/moderation/infractions.py
index 76f39d13c..592ead60f 100644
--- a/bot/cogs/moderation/infractions.py
+++ b/bot/cogs/moderation/infractions.py
@@ -12,7 +12,6 @@ from discord.ext.commands import Context, command
from bot import constants
from bot.api import ResponseCodeError
from bot.constants import Colours, Event
-from bot.converters import Duration
from bot.decorators import respect_role_hierarchy
from bot.utils import time
from bot.utils.checks import with_role_check
@@ -113,7 +112,7 @@ class Infractions(Scheduler, commands.Cog):
# region: Temporary infractions
@command(aliases=["mute"])
- async def tempmute(self, ctx: Context, user: Member, duration: Duration, *, reason: str = None) -> None:
+ async def tempmute(self, ctx: Context, user: Member, duration: utils.Expiry, *, reason: str = None) -> None:
"""
Temporarily mute a user for the given reason and duration.
@@ -126,11 +125,13 @@ class Infractions(Scheduler, commands.Cog):
\u2003`h` - hours
\u2003`M` - minutes∗
\u2003`s` - seconds
+
+ Alternatively, an ISO 8601 timestamp can be provided for the duration.
"""
await self.apply_mute(ctx, user, reason, expires_at=duration)
@command()
- async def tempban(self, ctx: Context, user: MemberConverter, duration: Duration, *, reason: str = None) -> None:
+ async def tempban(self, ctx: Context, user: MemberConverter, duration: utils.Expiry, *, reason: str = None) -> None:
"""
Temporarily ban a user for the given reason and duration.
@@ -143,6 +144,8 @@ class Infractions(Scheduler, commands.Cog):
\u2003`h` - hours
\u2003`M` - minutes∗
\u2003`s` - seconds
+
+ Alternatively, an ISO 8601 timestamp can be provided for the duration.
"""
await self.apply_ban(ctx, user, reason, expires_at=duration)
@@ -172,9 +175,7 @@ class Infractions(Scheduler, commands.Cog):
# region: Temporary shadow infractions
@command(hidden=True, aliases=["shadowtempmute, stempmute", "shadowmute", "smute"])
- async def shadow_tempmute(
- self, ctx: Context, user: Member, duration: Duration, *, reason: str = None
- ) -> None:
+ async def shadow_tempmute(self, ctx: Context, user: Member, duration: utils.Expiry, *, reason: str = None) -> None:
"""
Temporarily mute a user for the given reason and duration without notifying the user.
@@ -187,12 +188,19 @@ class Infractions(Scheduler, commands.Cog):
\u2003`h` - hours
\u2003`M` - minutes∗
\u2003`s` - seconds
+
+ Alternatively, an ISO 8601 timestamp can be provided for the duration.
"""
await self.apply_mute(ctx, user, reason, expires_at=duration, hidden=True)
@command(hidden=True, aliases=["shadowtempban, stempban"])
async def shadow_tempban(
- self, ctx: Context, user: MemberConverter, duration: Duration, *, reason: str = None
+ self,
+ ctx: Context,
+ user: MemberConverter,
+ duration: utils.Expiry,
+ *,
+ reason: str = None
) -> None:
"""
Temporarily ban a user for the given reason and duration without notifying the user.
@@ -206,6 +214,8 @@ class Infractions(Scheduler, commands.Cog):
\u2003`h` - hours
\u2003`M` - minutes∗
\u2003`s` - seconds
+
+ Alternatively, an ISO 8601 timestamp can be provided for the duration.
"""
await self.apply_ban(ctx, user, reason, expires_at=duration, hidden=True)
@@ -310,7 +320,8 @@ class Infractions(Scheduler, commands.Cog):
log_content = None
log_text = {
"Member": str(user_id),
- "Actor": str(self.bot.user)
+ "Actor": str(self.bot.user),
+ "Reason": infraction["reason"]
}
try:
@@ -355,6 +366,22 @@ class Infractions(Scheduler, commands.Cog):
log_text["Failure"] = f"HTTPException with code {e.code}."
log_content = mod_role.mention
+ # Check if the user is currently being watched by Big Brother.
+ try:
+ active_watch = await self.bot.api_client.get(
+ "bot/infractions",
+ params={
+ "active": "true",
+ "type": "watch",
+ "user__id": user_id
+ }
+ )
+
+ log_text["Watching"] = "Yes" if active_watch else "No"
+ except ResponseCodeError:
+ log.exception(f"Failed to fetch watch status for user {user_id}")
+ log_text["Watching"] = "Unknown - failed to fetch watch status."
+
try:
# Mark infraction as inactive in the database.
await self.bot.api_client.patch(
@@ -415,7 +442,6 @@ class Infractions(Scheduler, commands.Cog):
expiry_log_text = f"Expires: {expiry}" if expiry else ""
log_title = "applied"
log_content = None
- reason_msg = ""
# DM the user about the infraction if it's not a shadow/hidden infraction.
if not infraction["hidden"]:
@@ -431,7 +457,13 @@ class Infractions(Scheduler, commands.Cog):
log_content = ctx.author.mention
if infraction["actor"] == self.bot.user.id:
- reason_msg = f" (reason: {infraction['reason']})"
+ end_msg = f" (reason: {infraction['reason']})"
+ else:
+ infractions = await self.bot.api_client.get(
+ "bot/infractions",
+ params={"user__id": str(user.id)}
+ )
+ end_msg = f" ({len(infractions)} infractions total)"
# Execute the necessary actions to apply the infraction on Discord.
if action_coro:
@@ -448,7 +480,9 @@ class Infractions(Scheduler, commands.Cog):
log_title = "failed to apply"
# Send a confirmation message to the invoking context.
- await ctx.send(f"{dm_result}{confirm_msg} **{infr_type}** to {user.mention}{expiry_msg}{reason_msg}.")
+ await ctx.send(
+ f"{dm_result}{confirm_msg} **{infr_type}** to {user.mention}{expiry_msg}{end_msg}."
+ )
# Send a log message to the mod log.
await self.mod_log.send_log_message(
diff --git a/bot/cogs/moderation/management.py b/bot/cogs/moderation/management.py
index cb266b608..491f6d400 100644
--- a/bot/cogs/moderation/management.py
+++ b/bot/cogs/moderation/management.py
@@ -8,7 +8,7 @@ from discord.ext import commands
from discord.ext.commands import Context
from bot import constants
-from bot.converters import Duration, InfractionSearchQuery
+from bot.converters import InfractionSearchQuery
from bot.pagination import LinePaginator
from bot.utils import time
from bot.utils.checks import with_role_check
@@ -60,7 +60,7 @@ class ModManagement(commands.Cog):
self,
ctx: Context,
infraction_id: int,
- expires_at: t.Union[Duration, permanent_duration, None],
+ duration: t.Union[utils.Expiry, permanent_duration, None],
*,
reason: str = None
) -> None:
@@ -77,9 +77,10 @@ class ModManagement(commands.Cog):
\u2003`M` - minutes∗
\u2003`s` - seconds
- Use "permanent" to mark the infraction as permanent.
+ Use "permanent" to mark the infraction as permanent. Alternatively, an ISO 8601 timestamp
+ can be provided for the duration.
"""
- if expires_at is None and reason is None:
+ if duration is None and reason is None:
# Unlike UserInputError, the error handler will show a specified message for BadArgument
raise commands.BadArgument("Neither a new expiry nor a new reason was specified.")
@@ -90,12 +91,12 @@ class ModManagement(commands.Cog):
confirm_messages = []
log_text = ""
- if expires_at == "permanent":
+ if duration == "permanent":
request_data['expires_at'] = None
confirm_messages.append("marked as permanent")
- elif expires_at is not None:
- request_data['expires_at'] = expires_at.isoformat()
- expiry = expires_at.strftime(time.INFRACTION_FORMAT)
+ elif duration is not None:
+ request_data['expires_at'] = duration.isoformat()
+ expiry = duration.strftime(time.INFRACTION_FORMAT)
confirm_messages.append(f"set to expire on {expiry}")
else:
confirm_messages.append("expiry unchanged")
diff --git a/bot/cogs/moderation/superstarify.py b/bot/cogs/moderation/superstarify.py
index f3fcf236b..ccc6395d9 100644
--- a/bot/cogs/moderation/superstarify.py
+++ b/bot/cogs/moderation/superstarify.py
@@ -8,7 +8,6 @@ from discord.errors import Forbidden
from discord.ext.commands import Bot, Cog, Context, command
from bot import constants
-from bot.converters import Duration
from bot.utils.checks import with_role_check
from bot.utils.time import format_infraction
from . import utils
@@ -144,21 +143,30 @@ class Superstarify(Cog):
)
@command(name='superstarify', aliases=('force_nick', 'star'))
- async def superstarify(
- self, ctx: Context, member: Member, expiration: Duration, reason: str = None
- ) -> None:
+ async def superstarify(self, ctx: Context, member: Member, duration: utils.Expiry, reason: str = None) -> None:
"""
Force a random superstar name (like Taylor Swift) to be the user's nickname for a specified duration.
- An optional reason can be provided.
+ A unit of time should be appended to the duration.
+ Units (∗case-sensitive):
+ \u2003`y` - years
+ \u2003`m` - months∗
+ \u2003`w` - weeks
+ \u2003`d` - days
+ \u2003`h` - hours
+ \u2003`M` - minutes∗
+ \u2003`s` - seconds
- If no reason is given, the original name will be shown in a generated reason.
+ Alternatively, an ISO 8601 timestamp can be provided for the duration.
+
+ An optional reason can be provided. If no reason is given, the original name will be shown
+ in a generated reason.
"""
if await utils.has_active_infraction(ctx, member, "superstar"):
return
reason = reason or ('old nick: ' + member.display_name)
- infraction = await utils.post_infraction(ctx, member, 'superstar', reason, expires_at=expiration)
+ infraction = await utils.post_infraction(ctx, member, 'superstar', reason, expires_at=duration)
forced_nick = self.get_nick(infraction['id'], member.id)
expiry_str = format_infraction(infraction["expires_at"])
diff --git a/bot/cogs/moderation/utils.py b/bot/cogs/moderation/utils.py
index e9c879b46..788a40d40 100644
--- a/bot/cogs/moderation/utils.py
+++ b/bot/cogs/moderation/utils.py
@@ -9,6 +9,7 @@ from discord.ext.commands import Context
from bot.api import ResponseCodeError
from bot.constants import Colours, Icons
+from bot.converters import Duration, ISODateTime
log = logging.getLogger(__name__)
@@ -26,6 +27,7 @@ APPEALABLE_INFRACTIONS = ("ban", "mute")
UserTypes = t.Union[discord.Member, discord.User]
MemberObject = t.Union[UserTypes, discord.Object]
Infraction = t.Dict[str, t.Union[str, int, bool]]
+Expiry = t.Union[Duration, ISODateTime]
def proxy_user(user_id: str) -> discord.Object: