aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--bot/exts/help_channels/_cog.py12
-rw-r--r--bot/exts/info/subscribe.py2
-rw-r--r--bot/exts/moderation/incidents.py1
-rw-r--r--bot/exts/moderation/infraction/_utils.py2
-rw-r--r--bot/exts/moderation/infraction/infractions.py87
-rw-r--r--bot/exts/moderation/modlog.py3
-rw-r--r--bot/exts/moderation/voice_gate.py4
-rw-r--r--bot/exts/utils/reminders.py15
-rw-r--r--bot/resources/tags/traceback.md21
-rw-r--r--poetry.lock34
-rw-r--r--pyproject.toml1
-rw-r--r--tests/bot/exts/moderation/infraction/test_infractions.py86
13 files changed, 137 insertions, 132 deletions
diff --git a/README.md b/README.md
index 9df905dc8..06df4fd9a 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,6 @@
[![Lint & Test][1]][2]
[![Build][3]][4]
[![Deploy][5]][6]
-[![Coverage Status](https://coveralls.io/repos/github/python-discord/bot/badge.svg)](https://coveralls.io/github/python-discord/bot)
[![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
This project is a Discord bot specifically for use with the Python Discord server. It provides numerous utilities
diff --git a/bot/exts/help_channels/_cog.py b/bot/exts/help_channels/_cog.py
index 60209ba6e..541c791e5 100644
--- a/bot/exts/help_channels/_cog.py
+++ b/bot/exts/help_channels/_cog.py
@@ -105,10 +105,18 @@ class HelpChannels(commands.Cog):
"""
Claim the channel in which the question `message` was sent.
- Move the channel to the In Use category and pin the `message`. Add a cooldown to the
- claimant to prevent them from asking another question. Lastly, make a new channel available.
+ Send an embed stating the claimant, move the channel to the In Use category, and pin the `message`.
+ Add a cooldown to the claimant to prevent them from asking another question.
+ Lastly, make a new channel available.
"""
log.info(f"Channel #{message.channel} was claimed by `{message.author.id}`.")
+
+ embed = discord.Embed(
+ description=f"Channel claimed by {message.author.mention}.",
+ color=constants.Colours.bright_green,
+ )
+ await message.channel.send(embed=embed)
+
await self.move_to_in_use(message.channel)
# Handle odd edge case of `message.author` not being a `discord.Member` (see bot#1839)
diff --git a/bot/exts/info/subscribe.py b/bot/exts/info/subscribe.py
index 1299d5d59..eff0c13b8 100644
--- a/bot/exts/info/subscribe.py
+++ b/bot/exts/info/subscribe.py
@@ -171,7 +171,7 @@ class Subscribe(commands.Cog):
self.assignable_roles.sort(key=operator.methodcaller("is_currently_available"), reverse=True)
@commands.cooldown(1, 10, commands.BucketType.member)
- @commands.command(name="subscribe")
+ @commands.command(name="subscribe", aliases=("unsubscribe",))
@redirect_output(
destination_channel=constants.Channels.bot_commands,
bypass_roles=constants.STAFF_PARTNERS_COMMUNITY_ROLES,
diff --git a/bot/exts/moderation/incidents.py b/bot/exts/moderation/incidents.py
index 77dfad255..b579416a6 100644
--- a/bot/exts/moderation/incidents.py
+++ b/bot/exts/moderation/incidents.py
@@ -229,6 +229,7 @@ async def make_message_link_embed(ctx: Context, message_link: str) -> Optional[d
),
timestamp=message.created_at
)
+ embed.set_author(name=message.author, icon_url=message.author.display_avatar.url)
embed.add_field(
name="Content",
value=shorten_text(message.content) if message.content else "[No Message Content]"
diff --git a/bot/exts/moderation/infraction/_utils.py b/bot/exts/moderation/infraction/_utils.py
index e683c9db4..4df833ffb 100644
--- a/bot/exts/moderation/infraction/_utils.py
+++ b/bot/exts/moderation/infraction/_utils.py
@@ -21,7 +21,7 @@ INFRACTION_ICONS = {
"note": (Icons.user_warn, None),
"superstar": (Icons.superstarify, Icons.unsuperstarify),
"warning": (Icons.user_warn, None),
- "voice_ban": (Icons.voice_state_red, Icons.voice_state_green),
+ "voice_mute": (Icons.voice_state_red, Icons.voice_state_green),
}
RULES_URL = "https://pythondiscord.com/pages/rules"
diff --git a/bot/exts/moderation/infraction/infractions.py b/bot/exts/moderation/infraction/infractions.py
index e495a94b3..7c0259b8e 100644
--- a/bot/exts/moderation/infraction/infractions.py
+++ b/bot/exts/moderation/infraction/infractions.py
@@ -27,7 +27,7 @@ class Infractions(InfractionScheduler, commands.Cog):
category_description = "Server moderation tools."
def __init__(self, bot: Bot):
- super().__init__(bot, supported_infractions={"ban", "kick", "mute", "note", "warning", "voice_ban"})
+ super().__init__(bot, supported_infractions={"ban", "kick", "mute", "note", "warning", "voice_mute"})
self.category = "Moderation"
self._muted_role = discord.Object(constants.Roles.muted)
@@ -107,8 +107,19 @@ class Infractions(InfractionScheduler, commands.Cog):
"""
await self.apply_ban(ctx, user, reason, 1, expires_at=duration)
- @command(aliases=('vban',))
- async def voiceban(
+ @command(aliases=("vban",))
+ async def voiceban(self, ctx: Context) -> None:
+ """
+ NOT IMPLEMENTED.
+
+ Permanently ban a user from joining voice channels.
+
+ If duration is specified, it temporarily voice bans that user for the given duration.
+ """
+ await ctx.send(":x: This command is not yet implemented. Maybe you meant to use `voicemute`?")
+
+ @command(aliases=("vmute",))
+ async def voicemute(
self,
ctx: Context,
user: UnambiguousMemberOrUser,
@@ -117,11 +128,11 @@ class Infractions(InfractionScheduler, commands.Cog):
reason: t.Optional[str]
) -> None:
"""
- Permanently ban user from using voice channels.
+ Permanently mute user in voice channels.
- If duration is specified, it temporarily voice bans that user for the given duration.
+ If duration is specified, it temporarily voice mutes that user for the given duration.
"""
- await self.apply_voice_ban(ctx, user, reason, expires_at=duration)
+ await self.apply_voice_mute(ctx, user, reason, expires_at=duration)
# endregion
# region: Temporary infractions
@@ -186,16 +197,25 @@ class Infractions(InfractionScheduler, commands.Cog):
await self.apply_ban(ctx, user, reason, expires_at=duration)
@command(aliases=("tempvban", "tvban"))
- async def tempvoiceban(
- self,
- ctx: Context,
- user: UnambiguousMemberOrUser,
- duration: Expiry,
- *,
- reason: t.Optional[str]
+ async def tempvoiceban(self, ctx: Context) -> None:
+ """
+ NOT IMPLEMENTED.
+
+ Temporarily voice bans that user for the given duration.
+ """
+ await ctx.send(":x: This command is not yet implemented. Maybe you meant to use `tempvoicemute`?")
+
+ @command(aliases=("tempvmute", "tvmute"))
+ async def tempvoicemute(
+ self,
+ ctx: Context,
+ user: UnambiguousMemberOrUser,
+ duration: Expiry,
+ *,
+ reason: t.Optional[str]
) -> None:
"""
- Temporarily voice ban a user for the given reason and duration.
+ Temporarily voice mute a user for the given reason and duration.
A unit of time should be appended to the duration.
Units (∗case-sensitive):
@@ -209,7 +229,7 @@ class Infractions(InfractionScheduler, commands.Cog):
Alternatively, an ISO 8601 timestamp can be provided for the duration.
"""
- await self.apply_voice_ban(ctx, user, reason, expires_at=duration)
+ await self.apply_voice_mute(ctx, user, reason, expires_at=duration)
# endregion
# region: Permanent shadow infractions
@@ -271,9 +291,18 @@ class Infractions(InfractionScheduler, commands.Cog):
await self.pardon_infraction(ctx, "ban", user)
@command(aliases=("uvban",))
- async def unvoiceban(self, ctx: Context, user: UnambiguousMemberOrUser) -> None:
- """Prematurely end the active voice ban infraction for the user."""
- await self.pardon_infraction(ctx, "voice_ban", user)
+ async def unvoiceban(self, ctx: Context) -> None:
+ """
+ NOT IMPLEMENTED.
+
+ Temporarily voice bans that user for the given duration.
+ """
+ await ctx.send(":x: This command is not yet implemented. Maybe you meant to use `unvoicemute`?")
+
+ @command(aliases=("uvmute",))
+ async def unvoicemute(self, ctx: Context, user: UnambiguousMemberOrUser) -> None:
+ """Prematurely end the active voice mute infraction for the user."""
+ await self.pardon_infraction(ctx, "voice_mute", user)
# endregion
# region: Base apply functions
@@ -395,12 +424,12 @@ class Infractions(InfractionScheduler, commands.Cog):
await bb_cog.apply_unwatch(ctx, user, bb_reason, send_message=False)
@respect_role_hierarchy(member_arg=2)
- async def apply_voice_ban(self, ctx: Context, user: MemberOrUser, reason: t.Optional[str], **kwargs) -> None:
- """Apply a voice ban infraction with kwargs passed to `post_infraction`."""
- if await _utils.get_active_infraction(ctx, user, "voice_ban"):
+ async def apply_voice_mute(self, ctx: Context, user: MemberOrUser, reason: t.Optional[str], **kwargs) -> None:
+ """Apply a voice mute infraction with kwargs passed to `post_infraction`."""
+ if await _utils.get_active_infraction(ctx, user, "voice_mute"):
return
- infraction = await _utils.post_infraction(ctx, user, "voice_ban", reason, active=True, **kwargs)
+ infraction = await _utils.post_infraction(ctx, user, "voice_mute", reason, active=True, **kwargs)
if infraction is None:
return
@@ -414,7 +443,7 @@ class Infractions(InfractionScheduler, commands.Cog):
if not isinstance(user, Member):
return
- await user.move_to(None, reason="Disconnected from voice to apply voiceban.")
+ await user.move_to(None, reason="Disconnected from voice to apply voice mute.")
await user.remove_roles(self._voice_verified_role, reason=reason)
await self.apply_infraction(ctx, infraction, user, action())
@@ -471,7 +500,7 @@ class Infractions(InfractionScheduler, commands.Cog):
return log_text
- async def pardon_voice_ban(
+ async def pardon_voice_mute(
self,
user_id: int,
guild: discord.Guild,
@@ -487,9 +516,9 @@ class Infractions(InfractionScheduler, commands.Cog):
# DM user about infraction expiration
notified = await _utils.notify_pardon(
user=user,
- title="Voice ban ended",
- content="You have been unbanned and can verify yourself again in the server.",
- icon_url=_utils.INFRACTION_ICONS["voice_ban"][1]
+ title="Voice mute ended",
+ content="You have been unmuted and can verify yourself again in the server.",
+ icon_url=_utils.INFRACTION_ICONS["voice_mute"][1]
)
log_text["DM"] = "Sent" if notified else "**Failed**"
@@ -514,8 +543,8 @@ class Infractions(InfractionScheduler, commands.Cog):
return await self.pardon_mute(user_id, guild, reason, notify=notify)
elif infraction["type"] == "ban":
return await self.pardon_ban(user_id, guild, reason)
- elif infraction["type"] == "voice_ban":
- return await self.pardon_voice_ban(user_id, guild, notify=notify)
+ elif infraction["type"] == "voice_mute":
+ return await self.pardon_voice_mute(user_id, guild, notify=notify)
# endregion
diff --git a/bot/exts/moderation/modlog.py b/bot/exts/moderation/modlog.py
index 2c01a4a21..54a08738c 100644
--- a/bot/exts/moderation/modlog.py
+++ b/bot/exts/moderation/modlog.py
@@ -729,6 +729,9 @@ class ModLog(Cog, name="ModLog"):
@Cog.listener()
async def on_raw_message_edit(self, event: discord.RawMessageUpdateEvent) -> None:
"""Log raw message edit event to message change log."""
+ if event.guild_id is None:
+ return # ignore DM edits
+
await self.bot.wait_until_guild_available()
try:
channel = self.bot.get_channel(int(event.data["channel_id"]))
diff --git a/bot/exts/moderation/voice_gate.py b/bot/exts/moderation/voice_gate.py
index a382b13d1..fa66b00dd 100644
--- a/bot/exts/moderation/voice_gate.py
+++ b/bot/exts/moderation/voice_gate.py
@@ -30,7 +30,7 @@ FAILED_MESSAGE = (
MESSAGE_FIELD_MAP = {
"joined_at": f"have been on the server for less than {GateConf.minimum_days_member} days",
- "voice_banned": "have an active voice ban infraction",
+ "voice_gate_blocked": "have an active voice infraction",
"total_messages": f"have sent less than {GateConf.minimum_messages} messages",
"activity_blocks": f"have been active for fewer than {GateConf.minimum_activity_blocks} ten-minute blocks",
}
@@ -170,7 +170,7 @@ class VoiceGate(Cog):
ctx.author.joined_at > arrow.utcnow() - timedelta(days=GateConf.minimum_days_member)
),
"total_messages": data["total_messages"] < GateConf.minimum_messages,
- "voice_banned": data["voice_banned"],
+ "voice_gate_blocked": data["voice_gate_blocked"],
"activity_blocks": data["activity_blocks"] < GateConf.minimum_activity_blocks,
}
diff --git a/bot/exts/utils/reminders.py b/bot/exts/utils/reminders.py
index 289d00356..ad82d49c9 100644
--- a/bot/exts/utils/reminders.py
+++ b/bot/exts/utils/reminders.py
@@ -66,20 +66,19 @@ class Reminders(Cog):
else:
self.schedule_reminder(reminder)
- def ensure_valid_reminder(self, reminder: dict) -> t.Tuple[bool, discord.User, discord.TextChannel]:
- """Ensure reminder author and channel can be fetched otherwise delete the reminder."""
- user = self.bot.get_user(reminder['author'])
+ def ensure_valid_reminder(self, reminder: dict) -> t.Tuple[bool, discord.TextChannel]:
+ """Ensure reminder channel can be fetched otherwise delete the reminder."""
channel = self.bot.get_channel(reminder['channel_id'])
is_valid = True
- if not user or not channel:
+ if not channel:
is_valid = False
log.info(
f"Reminder {reminder['id']} invalid: "
- f"User {reminder['author']}={user}, Channel {reminder['channel_id']}={channel}."
+ f"Channel {reminder['channel_id']}={channel}."
)
scheduling.create_task(self.bot.api_client.delete(f"bot/reminders/{reminder['id']}"))
- return is_valid, user, channel
+ return is_valid, channel
@staticmethod
async def _send_confirmation(
@@ -170,7 +169,7 @@ class Reminders(Cog):
@lock_arg(LOCK_NAMESPACE, "reminder", itemgetter("id"), raise_error=True)
async def send_reminder(self, reminder: dict, expected_time: t.Optional[time.Timestamp] = None) -> None:
"""Send the reminder."""
- is_valid, user, channel = self.ensure_valid_reminder(reminder)
+ is_valid, channel = self.ensure_valid_reminder(reminder)
if not is_valid:
# No need to cancel the task too; it'll simply be done once this coroutine returns.
return
@@ -206,7 +205,7 @@ class Reminders(Cog):
f"There was an error when trying to reply to a reminder invocation message, {e}, "
"fall back to using jump_url"
)
- await channel.send(content=f"{user.mention} {additional_mentions}", embed=embed)
+ await channel.send(content=f"<@{reminder['author']}> {additional_mentions}", embed=embed)
log.debug(f"Deleting reminder #{reminder['id']} (the user has been reminded).")
await self.bot.api_client.delete(f"bot/reminders/{reminder['id']}")
diff --git a/bot/resources/tags/traceback.md b/bot/resources/tags/traceback.md
index 321737aac..e21fa6c6e 100644
--- a/bot/resources/tags/traceback.md
+++ b/bot/resources/tags/traceback.md
@@ -1,18 +1,15 @@
Please provide the full traceback for your exception in order to help us identify your issue.
+While the last line of the error message tells us what kind of error you got,
+the full traceback will tell us which line, and other critical information to solve your problem.
+Please avoid screenshots so we can copy and paste parts of the message.
A full traceback could look like:
```py
Traceback (most recent call last):
- File "tiny", line 3, in
- do_something()
- File "tiny", line 2, in do_something
- a = 6 / b
-ZeroDivisionError: division by zero
+ File "my_file.py", line 5, in <module>
+ add_three("6")
+ File "my_file.py", line 2, in add_three
+ a = num + 3
+TypeError: can only concatenate str (not "int") to str
```
-The best way to read your traceback is bottom to top.
-
-• Identify the exception raised (in this case `ZeroDivisionError`)
-• Make note of the line number (in this case `2`), and navigate there in your program.
-• Try to understand why the error occurred (in this case because `b` is `0`).
-
-To read more about exceptions and errors, please refer to the [PyDis Wiki](https://pythondiscord.com/pages/guides/pydis-guides/asking-good-questions/#examining-tracebacks) or the [official Python tutorial](https://docs.python.org/3.7/tutorial/errors.html).
+If the traceback is long, use [our pastebin](https://paste.pythondiscord.com/).
diff --git a/poetry.lock b/poetry.lock
index 9c9cc97ad..6d3bd44bb 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -155,6 +155,7 @@ python-versions = "3.9.*"
[package.source]
type = "url"
url = "https://github.com/python-discord/bot-core/archive/511bcba1b0196cd498c707a525ea56921bd971db.zip"
+
[[package]]
name = "certifi"
version = "2021.10.8"
@@ -235,22 +236,6 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
toml = ["toml"]
[[package]]
-name = "coveralls"
-version = "2.2.0"
-description = "Show coverage stats online via coveralls.io"
-category = "dev"
-optional = false
-python-versions = ">= 3.5"
-
-[package.dependencies]
-coverage = ">=4.1,<6.0"
-docopt = ">=0.6.1"
-requests = ">=1.0.0"
-
-[package.extras]
-yaml = ["PyYAML (>=3.10)"]
-
-[[package]]
name = "deepdiff"
version = "4.3.2"
description = "Deep Difference and Search of any Python object/data."
@@ -307,14 +292,6 @@ optional = false
python-versions = "*"
[[package]]
-name = "docopt"
-version = "0.6.2"
-description = "Pythonic argument parser, that will make you smile"
-category = "dev"
-optional = false
-python-versions = "*"
-
-[[package]]
name = "emoji"
version = "0.6.0"
description = "Emoji for Python"
@@ -1170,7 +1147,7 @@ multidict = ">=4.0"
[metadata]
lock-version = "1.1"
python-versions = "3.9.*"
-content-hash = "d625aaae916c07c21080bf504831f5bf4d2bf4f0e3696e404448b43719eff201"
+content-hash = "0248fc7488c79af0cdb3a6db9528f4c3129db50b3a8d1dd3ba57dbc31b381c31"
[metadata.files]
aio-pika = [
@@ -1383,10 +1360,6 @@ coverage = [
{file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"},
{file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"},
]
-coveralls = [
- {file = "coveralls-2.2.0-py2.py3-none-any.whl", hash = "sha256:2301a19500b06649d2ec4f2858f9c69638d7699a4c63027c5d53daba666147cc"},
- {file = "coveralls-2.2.0.tar.gz", hash = "sha256:b990ba1f7bc4288e63340be0433698c1efe8217f78c689d254c2540af3d38617"},
-]
deepdiff = [
{file = "deepdiff-4.3.2-py3-none-any.whl", hash = "sha256:59fc1e3e7a28dd0147b0f2b00e3e27181f0f0ef4286b251d5f214a5bcd9a9bc4"},
{file = "deepdiff-4.3.2.tar.gz", hash = "sha256:91360be1d9d93b1d9c13ae9c5048fa83d9cff17a88eb30afaa0d7ff2d0fee17d"},
@@ -1400,9 +1373,6 @@ distlib = [
{file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
{file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"},
]
-docopt = [
- {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"},
-]
emoji = [
{file = "emoji-0.6.0.tar.gz", hash = "sha256:e42da4f8d648f8ef10691bc246f682a1ec6b18373abfd9be10ec0b398823bd11"},
]
diff --git a/pyproject.toml b/pyproject.toml
index 19e5f78a7..c764910c2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -36,7 +36,6 @@ tldextract = "^3.1.2"
[tool.poetry.dev-dependencies]
coverage = "~=5.0"
-coveralls = "~=2.1"
flake8 = "~=3.8"
flake8-annotations = "~=2.0"
flake8-bugbear = "~=20.1"
diff --git a/tests/bot/exts/moderation/infraction/test_infractions.py b/tests/bot/exts/moderation/infraction/test_infractions.py
index 4d01e18a5..f89465f84 100644
--- a/tests/bot/exts/moderation/infraction/test_infractions.py
+++ b/tests/bot/exts/moderation/infraction/test_infractions.py
@@ -62,8 +62,8 @@ class TruncationTests(unittest.IsolatedAsyncioTestCase):
@patch("bot.exts.moderation.infraction.infractions.constants.Roles.voice_verified", new=123456)
-class VoiceBanTests(unittest.IsolatedAsyncioTestCase):
- """Tests for voice ban related functions and commands."""
+class VoiceMuteTests(unittest.IsolatedAsyncioTestCase):
+ """Tests for voice mute related functions and commands."""
def setUp(self):
self.bot = MockBot()
@@ -73,59 +73,59 @@ class VoiceBanTests(unittest.IsolatedAsyncioTestCase):
self.ctx = MockContext(bot=self.bot, author=self.mod)
self.cog = Infractions(self.bot)
- async def test_permanent_voice_ban(self):
- """Should call voice ban applying function without expiry."""
- self.cog.apply_voice_ban = AsyncMock()
- self.assertIsNone(await self.cog.voiceban(self.cog, self.ctx, self.user, reason="foobar"))
- self.cog.apply_voice_ban.assert_awaited_once_with(self.ctx, self.user, "foobar", expires_at=None)
+ async def test_permanent_voice_mute(self):
+ """Should call voice mute applying function without expiry."""
+ self.cog.apply_voice_mute = AsyncMock()
+ self.assertIsNone(await self.cog.voicemute(self.cog, self.ctx, self.user, reason="foobar"))
+ self.cog.apply_voice_mute.assert_awaited_once_with(self.ctx, self.user, "foobar", expires_at=None)
- async def test_temporary_voice_ban(self):
- """Should call voice ban applying function with expiry."""
- self.cog.apply_voice_ban = AsyncMock()
- self.assertIsNone(await self.cog.tempvoiceban(self.cog, self.ctx, self.user, "baz", reason="foobar"))
- self.cog.apply_voice_ban.assert_awaited_once_with(self.ctx, self.user, "foobar", expires_at="baz")
+ async def test_temporary_voice_mute(self):
+ """Should call voice mute applying function with expiry."""
+ self.cog.apply_voice_mute = AsyncMock()
+ self.assertIsNone(await self.cog.tempvoicemute(self.cog, self.ctx, self.user, "baz", reason="foobar"))
+ self.cog.apply_voice_mute.assert_awaited_once_with(self.ctx, self.user, "foobar", expires_at="baz")
- async def test_voice_unban(self):
+ async def test_voice_unmute(self):
"""Should call infraction pardoning function."""
self.cog.pardon_infraction = AsyncMock()
- self.assertIsNone(await self.cog.unvoiceban(self.cog, self.ctx, self.user))
- self.cog.pardon_infraction.assert_awaited_once_with(self.ctx, "voice_ban", self.user)
+ self.assertIsNone(await self.cog.unvoicemute(self.cog, self.ctx, self.user))
+ self.cog.pardon_infraction.assert_awaited_once_with(self.ctx, "voice_mute", self.user)
@patch("bot.exts.moderation.infraction.infractions._utils.post_infraction")
@patch("bot.exts.moderation.infraction.infractions._utils.get_active_infraction")
- async def test_voice_ban_user_have_active_infraction(self, get_active_infraction, post_infraction_mock):
- """Should return early when user already have Voice Ban infraction."""
+ async def test_voice_mute_user_have_active_infraction(self, get_active_infraction, post_infraction_mock):
+ """Should return early when user already have Voice Mute infraction."""
get_active_infraction.return_value = {"foo": "bar"}
- self.assertIsNone(await self.cog.apply_voice_ban(self.ctx, self.user, "foobar"))
- get_active_infraction.assert_awaited_once_with(self.ctx, self.user, "voice_ban")
+ self.assertIsNone(await self.cog.apply_voice_mute(self.ctx, self.user, "foobar"))
+ get_active_infraction.assert_awaited_once_with(self.ctx, self.user, "voice_mute")
post_infraction_mock.assert_not_awaited()
@patch("bot.exts.moderation.infraction.infractions._utils.post_infraction")
@patch("bot.exts.moderation.infraction.infractions._utils.get_active_infraction")
- async def test_voice_ban_infraction_post_failed(self, get_active_infraction, post_infraction_mock):
+ async def test_voice_mute_infraction_post_failed(self, get_active_infraction, post_infraction_mock):
"""Should return early when posting infraction fails."""
self.cog.mod_log.ignore = MagicMock()
get_active_infraction.return_value = None
post_infraction_mock.return_value = None
- self.assertIsNone(await self.cog.apply_voice_ban(self.ctx, self.user, "foobar"))
+ self.assertIsNone(await self.cog.apply_voice_mute(self.ctx, self.user, "foobar"))
post_infraction_mock.assert_awaited_once()
self.cog.mod_log.ignore.assert_not_called()
@patch("bot.exts.moderation.infraction.infractions._utils.post_infraction")
@patch("bot.exts.moderation.infraction.infractions._utils.get_active_infraction")
- async def test_voice_ban_infraction_post_add_kwargs(self, get_active_infraction, post_infraction_mock):
- """Should pass all kwargs passed to apply_voice_ban to post_infraction."""
+ async def test_voice_mute_infraction_post_add_kwargs(self, get_active_infraction, post_infraction_mock):
+ """Should pass all kwargs passed to apply_voice_mute to post_infraction."""
get_active_infraction.return_value = None
# We don't want that this continue yet
post_infraction_mock.return_value = None
- self.assertIsNone(await self.cog.apply_voice_ban(self.ctx, self.user, "foobar", my_kwarg=23))
+ self.assertIsNone(await self.cog.apply_voice_mute(self.ctx, self.user, "foobar", my_kwarg=23))
post_infraction_mock.assert_awaited_once_with(
- self.ctx, self.user, "voice_ban", "foobar", active=True, my_kwarg=23
+ self.ctx, self.user, "voice_mute", "foobar", active=True, my_kwarg=23
)
@patch("bot.exts.moderation.infraction.infractions._utils.post_infraction")
@patch("bot.exts.moderation.infraction.infractions._utils.get_active_infraction")
- async def test_voice_ban_mod_log_ignore(self, get_active_infraction, post_infraction_mock):
+ async def test_voice_mute_mod_log_ignore(self, get_active_infraction, post_infraction_mock):
"""Should ignore Voice Verified role removing."""
self.cog.mod_log.ignore = MagicMock()
self.cog.apply_infraction = AsyncMock()
@@ -134,11 +134,11 @@ class VoiceBanTests(unittest.IsolatedAsyncioTestCase):
get_active_infraction.return_value = None
post_infraction_mock.return_value = {"foo": "bar"}
- self.assertIsNone(await self.cog.apply_voice_ban(self.ctx, self.user, "foobar"))
+ self.assertIsNone(await self.cog.apply_voice_mute(self.ctx, self.user, "foobar"))
self.cog.mod_log.ignore.assert_called_once_with(Event.member_update, self.user.id)
async def action_tester(self, action, reason: str) -> None:
- """Helper method to test voice ban action."""
+ """Helper method to test voice mute action."""
self.assertTrue(inspect.iscoroutine(action))
await action
@@ -147,7 +147,7 @@ class VoiceBanTests(unittest.IsolatedAsyncioTestCase):
@patch("bot.exts.moderation.infraction.infractions._utils.post_infraction")
@patch("bot.exts.moderation.infraction.infractions._utils.get_active_infraction")
- async def test_voice_ban_apply_infraction(self, get_active_infraction, post_infraction_mock):
+ async def test_voice_mute_apply_infraction(self, get_active_infraction, post_infraction_mock):
"""Should ignore Voice Verified role removing."""
self.cog.mod_log.ignore = MagicMock()
self.cog.apply_infraction = AsyncMock()
@@ -156,22 +156,22 @@ class VoiceBanTests(unittest.IsolatedAsyncioTestCase):
post_infraction_mock.return_value = {"foo": "bar"}
reason = "foobar"
- self.assertIsNone(await self.cog.apply_voice_ban(self.ctx, self.user, reason))
+ self.assertIsNone(await self.cog.apply_voice_mute(self.ctx, self.user, reason))
self.cog.apply_infraction.assert_awaited_once_with(self.ctx, {"foo": "bar"}, self.user, ANY)
await self.action_tester(self.cog.apply_infraction.call_args[0][-1], reason)
@patch("bot.exts.moderation.infraction.infractions._utils.post_infraction")
@patch("bot.exts.moderation.infraction.infractions._utils.get_active_infraction")
- async def test_voice_ban_truncate_reason(self, get_active_infraction, post_infraction_mock):
- """Should truncate reason for voice ban."""
+ async def test_voice_mute_truncate_reason(self, get_active_infraction, post_infraction_mock):
+ """Should truncate reason for voice mute."""
self.cog.mod_log.ignore = MagicMock()
self.cog.apply_infraction = AsyncMock()
get_active_infraction.return_value = None
post_infraction_mock.return_value = {"foo": "bar"}
- self.assertIsNone(await self.cog.apply_voice_ban(self.ctx, self.user, "foobar" * 3000))
+ self.assertIsNone(await self.cog.apply_voice_mute(self.ctx, self.user, "foobar" * 3000))
self.cog.apply_infraction.assert_awaited_once_with(self.ctx, {"foo": "bar"}, self.user, ANY)
# Test action
@@ -180,14 +180,14 @@ class VoiceBanTests(unittest.IsolatedAsyncioTestCase):
@autospec(_utils, "post_infraction", "get_active_infraction", return_value=None)
@autospec(Infractions, "apply_infraction")
- async def test_voice_ban_user_left_guild(self, apply_infraction_mock, post_infraction_mock, _):
- """Should voice ban user that left the guild without throwing an error."""
+ async def test_voice_mute_user_left_guild(self, apply_infraction_mock, post_infraction_mock, _):
+ """Should voice mute user that left the guild without throwing an error."""
infraction = {"foo": "bar"}
post_infraction_mock.return_value = {"foo": "bar"}
user = MockUser()
- await self.cog.voiceban(self.cog, self.ctx, user, reason=None)
- post_infraction_mock.assert_called_once_with(self.ctx, user, "voice_ban", None, active=True, expires_at=None)
+ await self.cog.voicemute(self.cog, self.ctx, user, reason=None)
+ post_infraction_mock.assert_called_once_with(self.ctx, user, "voice_mute", None, active=True, expires_at=None)
apply_infraction_mock.assert_called_once_with(self.cog, self.ctx, infraction, user, ANY)
# Test action
@@ -195,22 +195,22 @@ class VoiceBanTests(unittest.IsolatedAsyncioTestCase):
self.assertTrue(inspect.iscoroutine(action))
await action
- async def test_voice_unban_user_not_found(self):
+ async def test_voice_unmute_user_not_found(self):
"""Should include info to return dict when user was not found from guild."""
self.guild.get_member.return_value = None
self.guild.fetch_member.side_effect = NotFound(Mock(status=404), "Not found")
- result = await self.cog.pardon_voice_ban(self.user.id, self.guild)
+ result = await self.cog.pardon_voice_mute(self.user.id, self.guild)
self.assertEqual(result, {"Info": "User was not found in the guild."})
@patch("bot.exts.moderation.infraction.infractions._utils.notify_pardon")
@patch("bot.exts.moderation.infraction.infractions.format_user")
- async def test_voice_unban_user_found(self, format_user_mock, notify_pardon_mock):
+ async def test_voice_unmute_user_found(self, format_user_mock, notify_pardon_mock):
"""Should add role back with ignoring, notify user and return log dictionary.."""
self.guild.get_member.return_value = self.user
notify_pardon_mock.return_value = True
format_user_mock.return_value = "my-user"
- result = await self.cog.pardon_voice_ban(self.user.id, self.guild)
+ result = await self.cog.pardon_voice_mute(self.user.id, self.guild)
self.assertEqual(result, {
"Member": "my-user",
"DM": "Sent"
@@ -219,13 +219,13 @@ class VoiceBanTests(unittest.IsolatedAsyncioTestCase):
@patch("bot.exts.moderation.infraction.infractions._utils.notify_pardon")
@patch("bot.exts.moderation.infraction.infractions.format_user")
- async def test_voice_unban_dm_fail(self, format_user_mock, notify_pardon_mock):
+ async def test_voice_unmute_dm_fail(self, format_user_mock, notify_pardon_mock):
"""Should add role back with ignoring, notify user and return log dictionary.."""
self.guild.get_member.return_value = self.user
notify_pardon_mock.return_value = False
format_user_mock.return_value = "my-user"
- result = await self.cog.pardon_voice_ban(self.user.id, self.guild)
+ result = await self.cog.pardon_voice_mute(self.user.id, self.guild)
self.assertEqual(result, {
"Member": "my-user",
"DM": "**Failed**"