Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 28 additions & 0 deletions docs/cog_guides/mutes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,34 @@ Examples:
* ``<users...>``: A space separated list of usernames, ID's, or mentions.
* ``[time_and_reason]``: The time and reason. If no time is provided, the mute will use the default set time or give an error if this hasn't been configured.

.. _mutes-command-untimeout:

^^^^^^^^^
untimeout
^^^^^^^^^

.. note:: |mod-lock|

**Syntax**

.. code-block:: none

[p]untimeout <users...> [reason]

**Description**

Remove a timeout from users.

Examples:

* ``[p]untimeout @member1 @member2 appealed``
* ``[p]untimeout @member1``

**Arguments**

* ``<users...>``: A space separated list of usernames, ID's, or mentions.
* ``[reason]``: The reason for removing the timeout.

.. _mutes-command-voicemute:

^^^^^^^^^
Expand Down
62 changes: 62 additions & 0 deletions redbot/cogs/mutes/mutes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,14 @@ async def timeout(
time = _(" for {length} until {duration}").format(
length=length, duration=discord.utils.format_dt(until)
)
else:
await ctx.send(
_(
"You must provide a duration for the timeout. "
"To remove a timeout, use `{prefix}untimeout`."
).format(prefix=ctx.clean_prefix)
)
return

success_list = []
issues_list = []
Expand Down Expand Up @@ -1203,6 +1211,60 @@ async def timeout(
if issues_list:
await self.handle_issues(ctx, issues_list)

@commands.command(usage="<users...> [reason]")
@commands.guild_only()
@commands.mod_or_permissions(moderate_members=True)
@commands.bot_has_permissions(moderate_members=True)
async def untimeout(
self,
ctx: commands.Context,
users: commands.Greedy[discord.Member],
*,
reason: Optional[str] = None,
):
"""Remove a timeout from users.

`<users...>` is a space separated list of usernames, ID's, or mentions.
`[reason]` is the reason for removing the timeout.

Examples:
`[p]untimeout @member1 @member2 appealed`
`[p]untimeout @member1`
"""
if not users:
return await ctx.send_help()
audit_reason = get_audit_reason(ctx.author, reason, shorten=True)
success_list = []
issues_list = []
for member in users:
ret = MuteResponse(success=False, reason=None, user=member)
if member.guild_permissions >= ctx.author.guild_permissions:
ret.reason = _(MUTE_UNMUTE_ISSUES["hierarchy_problem"])
issues_list.append(ret)
continue
if not member.is_timed_out():
ret.reason = _("That user is not currently timed out.")
issues_list.append(ret)
continue
try:
await member.edit(timed_out_until=None, reason=audit_reason)
success_list.append(member)
except discord.Forbidden:
ret.reason = _("I do not have permission to remove this user's timeout.")
issues_list.append(ret)
except discord.HTTPException as e:
ret.reason = _("Unexpected error: {error}").format(error=str(e))
issues_list.append(ret)
if success_list:
msg = _("{users} has had their timeout removed.")
if len(success_list) > 1:
msg = _("{users} have had their timeouts removed.")
await ctx.send(msg.format(users=humanize_list([f"`{u}`" for u in success_list])))
else:
await ctx.send(_("None of the users provided could have their timeout removed."))
if issues_list:
await self.handle_issues(ctx, issues_list)

@commands.command(usage="<users...> [time_and_reason]")
@commands.guild_only()
@commands.mod_or_permissions(manage_roles=True, moderate_members=True)
Expand Down
Loading