aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/cogs/moderation.py91
-rw-r--r--bot/constants.py3
-rw-r--r--config-default.yml1
3 files changed, 91 insertions, 4 deletions
diff --git a/bot/cogs/moderation.py b/bot/cogs/moderation.py
index f2ab64850..8829c595d 100644
--- a/bot/cogs/moderation.py
+++ b/bot/cogs/moderation.py
@@ -248,14 +248,91 @@ class Moderation:
await ctx.send(result_message)
+ @with_role(Roles.admin, Roles.owner, Roles.moderator)
+ @command(name="moderation.unmute")
+ async def unmute(self, ctx, user: Member):
+ """
+ Deactivates the active mute infraction for a user.
+ :param user: Accepts user mention, ID, etc.
+ """
+ try:
+ # check the current active infraction
+ response = await self.bot.http_session.get(
+ URLs.site_infractions_user_type_current.format(
+ user_id=user.id,
+ infraction_type="mute"
+ ),
+ headers=self.headers
+ )
+ response_object = await response.json()
+ if "error_code" in response_object:
+ # something went wrong
+ await ctx.send(f":x: There was an error removing the infraction: {response_object['error_message']}")
+ return
+
+ infraction_object = response_object["infraction"]
+ if infraction_object is None:
+ # no active infraction
+ await ctx.send(f":x: There is no active mute infraction for user {user.mention}.")
+ return
+
+ await self._deactivate_infraction(infraction_object)
+ if infraction_object["expires_at"] is not None:
+ self.cancel_expiration(infraction_object["id"])
+
+ await ctx.send(f":ok_hand: Un-muted {user.mention}.")
+ except Exception:
+ log.exception("There was an error removing an infraction.")
+ await ctx.send(":x: There was an error removing the infraction.")
+ return
+
+ @with_role(Roles.admin, Roles.owner, Roles.moderator)
+ @command(name="moderation.unban")
+ async def unban(self, ctx, user: User):
+ """
+ Deactivates the active ban infraction for a user.
+ :param user: Accepts user mention, ID, etc.
+ """
+ try:
+ # check the current active infraction
+ response = await self.bot.http_session.get(
+ URLs.site_infractions_user_type_current.format(
+ user_id=user.id,
+ infraction_type="ban"
+ ),
+ headers=self.headers
+ )
+ response_object = await response.json()
+ if "error_code" in response_object:
+ # something went wrong
+ await ctx.send(f":x: There was an error removing the infraction: {response_object['error_message']}")
+ return
+
+ infraction_object = response_object["infraction"]
+ if infraction_object is None:
+ # no active infraction
+ await ctx.send(f":x: There is no active ban infraction for user {user.mention}.")
+ return
+
+ await self._deactivate_infraction(infraction_object, user=user)
+ if infraction_object["expires_at"] is not None:
+ self.cancel_expiration(infraction_object["id"])
+
+ await ctx.send(f":ok_hand: Un-banned {user.mention}.")
+ except Exception:
+ log.exception("There was an error removing an infraction.")
+ await ctx.send(":x: There was an error removing the infraction.")
+ return
+
def schedule_expiration(self, loop: asyncio.AbstractEventLoop, infraction_object: dict):
infraction_id = infraction_object["id"]
if infraction_id in self.expiration_tasks:
return
task: asyncio.Task = asyncio.ensure_future(self._scheduled_expiration(infraction_object), loop=loop)
+
# Silently ignore exceptions in a callback (handles the CancelledError nonsense)
- task.add_done_callback(lambda future: future.exception())
+ task.add_done_callback(_silent_exception)
self.expiration_tasks[infraction_id] = task
@@ -285,7 +362,7 @@ class Moderation:
self.cancel_expiration(infraction_object["id"])
- async def _deactivate_infraction(self, infraction_object):
+ async def _deactivate_infraction(self, infraction_object, user: User = None):
guild: Guild = self.bot.get_guild(constants.Guild.id)
user_id = infraction_object["user"]["user_id"]
infraction_type = infraction_object["type"]
@@ -295,7 +372,8 @@ class Moderation:
if member:
await member.edit(mute=False)
elif infraction_type == "ban":
- user: User = self.bot.get_user(user_id)
+ if user is None:
+ user: User = self.bot.get_user(user_id)
await guild.unban(user)
await self.bot.http_session.patch(
@@ -315,6 +393,13 @@ def parse_rfc1123(time_str):
return datetime.datetime.strptime(time_str, RFC1123_FORMAT).replace(tzinfo=datetime.timezone.utc)
+def _silent_exception(future):
+ try:
+ future.exception()
+ except Exception:
+ pass
+
+
def setup(bot):
bot.add_cog(Moderation(bot))
# Here we'll need to call a command I haven't made yet
diff --git a/bot/constants.py b/bot/constants.py
index c435fbad9..915373add 100644
--- a/bot/constants.py
+++ b/bot/constants.py
@@ -265,7 +265,8 @@ class URLs(metaclass=YAMLGetter):
site_infractions: str
site_infractions_user: str
site_infractions_type: str
- site_infractions_by_id: str
+ site_infractions_user_type_current: str
+ site_infractions_user_type: str
status: str
paste_service: str
diff --git a/config-default.yml b/config-default.yml
index 8f0c32af9..15cdd948c 100644
--- a/config-default.yml
+++ b/config-default.yml
@@ -89,5 +89,6 @@ urls:
site_infractions_user: 'https://api.pythondiscord.com/bot/infractions/user/{user_id}'
site_infractions_type: 'https://api.pythondiscord.com/bot/infractions/type/{infraction_type}'
site_infractions_by_id: 'https://api.pythondiscord.com/bot/infractions/id/{infraction_id}'
+ site_infractions_user_type_current: 'https://api.pythondiscord.com/bot/infractions/user/{user_id}/{infraction_type}/current'
status: !ENV 'STATUS_URL'
paste_service: 'https://paste.pydis.com/{key}'