From 38d9e705c77003008f1562188cba079a4245061b Mon Sep 17 00:00:00 2001 From: kwzrd Date: Fri, 1 Nov 2019 23:01:45 +0100 Subject: Add unit test for links antispam rule --- tests/bot/rules/test_links.py | 93 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 tests/bot/rules/test_links.py diff --git a/tests/bot/rules/test_links.py b/tests/bot/rules/test_links.py new file mode 100644 index 000000000..f71a8e6bb --- /dev/null +++ b/tests/bot/rules/test_links.py @@ -0,0 +1,93 @@ +import unittest +from typing import List, NamedTuple, Tuple + +from bot.rules import links +from tests.helpers import async_test + + +class FakeMessage(NamedTuple): + author: str + content: str + + +class Case(NamedTuple): + recent_messages: List[FakeMessage] + relevant_messages: Tuple[FakeMessage] + culprit: Tuple[str] + total_links: int + + +def msg(author: str, total_links: int) -> FakeMessage: + """Makes a message with `total_links` links.""" + content = " ".join(["https://pydis.com"] * total_links) + return FakeMessage(author=author, content=content) + + +class LinksTests(unittest.TestCase): + """Tests applying the `links` rule.""" + + def setUp(self): + self.config = { + "max": 2, + "interval": 10 + } + + @async_test + async def test_links_within_limit(self): + """Messages with an allowed amount of links.""" + cases = ( + [msg("bob", 0)], + [msg("bob", 2)], + [msg("bob", 3)], + [msg("bob", 3), msg("alice", 3)] + ) + + for recent_messages in cases: + last_message = recent_messages[0] + with self.subTest( + last_message=last_message, + recent_messages=recent_messages, + config=self.config + ): + self.assertIsNone( + await links.apply(last_message, recent_messages, self.config) + ) + + @async_test + async def test_links_exceeding_limit(self): + """Messages with a a higher than allowed amount of links.""" + cases = ( + Case( + [msg("bob", 1), msg("bob", 2)], + (msg("bob", 1), msg("bob", 2)), + ("bob",), + 3 + ), + Case( + [msg("alice", 2), msg("bob", 3), msg("alice", 1)], + (msg("alice", 2), msg("alice", 1)), + ("alice",), + 3 + ) + ) + + for recent_messages, relevant_messages, culprit, total_links in cases: + last_message = recent_messages[0] + + with self.subTest( + last_message=last_message, + recent_messages=recent_messages, + relevant_messages=relevant_messages, + culprit=culprit, + total_links=total_links, + config=self.config + ): + desired_output = ( + f"sent {total_links} links in {self.config['interval']}s", + culprit, + relevant_messages + ) + self.assertTupleEqual( + await links.apply(last_message, recent_messages, self.config), + desired_output + ) -- cgit v1.2.3 From a21670459953599c8f13286595520e033da4199a Mon Sep 17 00:00:00 2001 From: kwzrd Date: Fri, 1 Nov 2019 23:24:20 +0100 Subject: Add two more test cases for links rule unit test --- tests/bot/rules/test_links.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/bot/rules/test_links.py b/tests/bot/rules/test_links.py index f71a8e6bb..f043495cf 100644 --- a/tests/bot/rules/test_links.py +++ b/tests/bot/rules/test_links.py @@ -39,6 +39,7 @@ class LinksTests(unittest.TestCase): [msg("bob", 0)], [msg("bob", 2)], [msg("bob", 3)], + [msg("bob", 1), msg("bob", 1)], [msg("bob", 3), msg("alice", 3)] ) @@ -63,6 +64,12 @@ class LinksTests(unittest.TestCase): ("bob",), 3 ), + Case( + [msg("alice", 1), msg("alice", 1), msg("alice", 1)], + (msg("alice", 1), msg("alice", 1), msg("alice", 1)), + ("alice",), + 3 + ), Case( [msg("alice", 2), msg("bob", 3), msg("alice", 1)], (msg("alice", 2), msg("alice", 1)), -- cgit v1.2.3 From 9e16b0cf17e93295167956d31ad9f92396ca3402 Mon Sep 17 00:00:00 2001 From: kwzrd Date: Sat, 2 Nov 2019 01:19:07 +0100 Subject: Annotate unclear test cases with inline comments --- tests/bot/rules/test_links.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bot/rules/test_links.py b/tests/bot/rules/test_links.py index f043495cf..a04b90c13 100644 --- a/tests/bot/rules/test_links.py +++ b/tests/bot/rules/test_links.py @@ -38,9 +38,9 @@ class LinksTests(unittest.TestCase): cases = ( [msg("bob", 0)], [msg("bob", 2)], - [msg("bob", 3)], + [msg("bob", 3)], # Filter only applies if len(messages_with_links) > 1 [msg("bob", 1), msg("bob", 1)], - [msg("bob", 3), msg("alice", 3)] + [msg("bob", 3), msg("alice", 3)] # Only messages from latest author count ) for recent_messages in cases: -- cgit v1.2.3 From f6ed29c8692759dc0c8b003ebf2d4ce3d5ca6ed9 Mon Sep 17 00:00:00 2001 From: kwzrd Date: Sat, 2 Nov 2019 01:34:46 +0100 Subject: Adjust case to only test a single aspect --- tests/bot/rules/test_links.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bot/rules/test_links.py b/tests/bot/rules/test_links.py index a04b90c13..95f107f91 100644 --- a/tests/bot/rules/test_links.py +++ b/tests/bot/rules/test_links.py @@ -40,7 +40,7 @@ class LinksTests(unittest.TestCase): [msg("bob", 2)], [msg("bob", 3)], # Filter only applies if len(messages_with_links) > 1 [msg("bob", 1), msg("bob", 1)], - [msg("bob", 3), msg("alice", 3)] # Only messages from latest author count + [msg("bob", 2), msg("alice", 2)] # Only messages from latest author count ) for recent_messages in cases: -- cgit v1.2.3 From 4dccacaa5794751546336de1aa42cd5a9095b706 Mon Sep 17 00:00:00 2001 From: Derek Date: Mon, 4 Nov 2019 17:48:48 -0500 Subject: Reword periodic #checkpoint message --- bot/cogs/verification.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/cogs/verification.py b/bot/cogs/verification.py index 5b115deaa..3d85edae6 100644 --- a/bot/cogs/verification.py +++ b/bot/cogs/verification.py @@ -31,7 +31,7 @@ If you'd like to unsubscribe from the announcement notifications, simply send `! PERIODIC_PING = ( f"@everyone To verify that you have read our rules, please type `{BotConfig.prefix}accept`." - f" Ping <@&{Roles.admin}> if you encounter any problems during the verification process." + f" If you encounter any problems during the verification process, ping the <@&{Roles.admin}> role in this channel." ) -- cgit v1.2.3 From a916ec15867187907abe9214eb4bfa12a9e982f4 Mon Sep 17 00:00:00 2001 From: kosayoda Date: Fri, 8 Nov 2019 11:58:21 +0800 Subject: Allow helpers to nominate people --- bot/cogs/watchchannels/talentpool.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/bot/cogs/watchchannels/talentpool.py b/bot/cogs/watchchannels/talentpool.py index 176c6f760..4ec42dcc1 100644 --- a/bot/cogs/watchchannels/talentpool.py +++ b/bot/cogs/watchchannels/talentpool.py @@ -7,14 +7,13 @@ from discord import Color, Embed, Member, User from discord.ext.commands import Bot, Cog, Context, group from bot.api import ResponseCodeError -from bot.constants import Channels, Guild, Roles, Webhooks +from bot.constants import Channels, Guild, MODERATION_ROLES, STAFF_ROLES, Webhooks from bot.decorators import with_role from bot.pagination import LinePaginator from bot.utils import time from .watchchannel import WatchChannel, proxy_user log = logging.getLogger(__name__) -STAFF_ROLES = Roles.owner, Roles.admin, Roles.moderator, Roles.helpers # <- In constants after the merge? class TalentPool(WatchChannel, Cog, name="Talentpool"): @@ -31,13 +30,13 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"): ) @group(name='talentpool', aliases=('tp', 'talent', 'nomination', 'n'), invoke_without_command=True) - @with_role(Roles.owner, Roles.admin, Roles.moderator) + @with_role(*MODERATION_ROLES) async def nomination_group(self, ctx: Context) -> None: """Highlights the activity of helper nominees by relaying their messages to the talent pool channel.""" await ctx.invoke(self.bot.get_command("help"), "talentpool") @nomination_group.command(name='watched', aliases=('all', 'list')) - @with_role(Roles.owner, Roles.admin, Roles.moderator) + @with_role(*MODERATION_ROLES) async def watched_command(self, ctx: Context, update_cache: bool = True) -> None: """ Shows the users that are currently being monitored in the talent pool. @@ -48,7 +47,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"): await self.list_watched_users(ctx, update_cache) @nomination_group.command(name='watch', aliases=('w', 'add', 'a')) - @with_role(Roles.owner, Roles.admin, Roles.moderator) + @with_role(*STAFF_ROLES) async def watch_command(self, ctx: Context, user: Union[Member, User, proxy_user], *, reason: str) -> None: """ Relay messages sent by the given `user` to the `#talent-pool` channel. @@ -113,7 +112,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"): await ctx.send(msg) @nomination_group.command(name='history', aliases=('info', 'search')) - @with_role(Roles.owner, Roles.admin, Roles.moderator) + @with_role(*MODERATION_ROLES) async def history_command(self, ctx: Context, user: Union[User, proxy_user]) -> None: """Shows the specified user's nomination history.""" result = await self.bot.api_client.get( @@ -142,7 +141,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"): ) @nomination_group.command(name='unwatch', aliases=('end', )) - @with_role(Roles.owner, Roles.admin, Roles.moderator) + @with_role(*MODERATION_ROLES) async def unwatch_command(self, ctx: Context, user: Union[User, proxy_user], *, reason: str) -> None: """ Ends the active nomination of the specified user with the given reason. @@ -170,13 +169,13 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"): self._remove_user(user.id) @nomination_group.group(name='edit', aliases=('e',), invoke_without_command=True) - @with_role(Roles.owner, Roles.admin, Roles.moderator) + @with_role(*MODERATION_ROLES) async def nomination_edit_group(self, ctx: Context) -> None: """Commands to edit nominations.""" await ctx.invoke(self.bot.get_command("help"), "talentpool", "edit") @nomination_edit_group.command(name='reason') - @with_role(Roles.owner, Roles.admin, Roles.moderator) + @with_role(*MODERATION_ROLES) async def edit_reason_command(self, ctx: Context, nomination_id: int, *, reason: str) -> None: """ Edits the reason/unnominate reason for the nomination with the given `id` depending on the status. -- cgit v1.2.3 From 25f7f6019772e22072a2e1d16d6c4ff57862022f Mon Sep 17 00:00:00 2001 From: kosayoda Date: Fri, 8 Nov 2019 12:11:47 +0800 Subject: Refactor bigbrother to use constants --- bot/cogs/watchchannels/bigbrother.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/cogs/watchchannels/bigbrother.py b/bot/cogs/watchchannels/bigbrother.py index c516508ca..49783bb09 100644 --- a/bot/cogs/watchchannels/bigbrother.py +++ b/bot/cogs/watchchannels/bigbrother.py @@ -6,7 +6,7 @@ from discord import User from discord.ext.commands import Bot, Cog, Context, group from bot.cogs.moderation.utils import post_infraction -from bot.constants import Channels, Roles, Webhooks +from bot.constants import Channels, MODERATION_ROLES, Webhooks from bot.decorators import with_role from .watchchannel import WatchChannel, proxy_user @@ -27,13 +27,13 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"): ) @group(name='bigbrother', aliases=('bb',), invoke_without_command=True) - @with_role(Roles.owner, Roles.admin, Roles.moderator) + @with_role(*MODERATION_ROLES) async def bigbrother_group(self, ctx: Context) -> None: """Monitors users by relaying their messages to the Big Brother watch channel.""" await ctx.invoke(self.bot.get_command("help"), "bigbrother") @bigbrother_group.command(name='watched', aliases=('all', 'list')) - @with_role(Roles.owner, Roles.admin, Roles.moderator) + @with_role(*MODERATION_ROLES) async def watched_command(self, ctx: Context, update_cache: bool = True) -> None: """ Shows the users that are currently being monitored by Big Brother. @@ -44,7 +44,7 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"): await self.list_watched_users(ctx, update_cache) @bigbrother_group.command(name='watch', aliases=('w',)) - @with_role(Roles.owner, Roles.admin, Roles.moderator) + @with_role(*MODERATION_ROLES) async def watch_command(self, ctx: Context, user: Union[User, proxy_user], *, reason: str) -> None: """ Relay messages sent by the given `user` to the `#big-brother` channel. @@ -91,7 +91,7 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"): await ctx.send(msg) @bigbrother_group.command(name='unwatch', aliases=('uw',)) - @with_role(Roles.owner, Roles.admin, Roles.moderator) + @with_role(*MODERATION_ROLES) async def unwatch_command(self, ctx: Context, user: Union[User, proxy_user], *, reason: str) -> None: """Stop relaying messages by the given `user`.""" active_watches = await self.bot.api_client.get( -- cgit v1.2.3 From 9000d92ab8ceaf855d23c0e6dfdb09d05a40e59a Mon Sep 17 00:00:00 2001 From: kwzrd Date: Fri, 8 Nov 2019 22:07:00 +0100 Subject: Add whitespace for readability, consistency & allure --- tests/bot/rules/test_links.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bot/rules/test_links.py b/tests/bot/rules/test_links.py index 95f107f91..40336beb0 100644 --- a/tests/bot/rules/test_links.py +++ b/tests/bot/rules/test_links.py @@ -45,6 +45,7 @@ class LinksTests(unittest.TestCase): for recent_messages in cases: last_message = recent_messages[0] + with self.subTest( last_message=last_message, recent_messages=recent_messages, -- cgit v1.2.3 From 760f265339b1462b60ea7d5af1fd8d4476c134f0 Mon Sep 17 00:00:00 2001 From: kwzrd <44734341+kwzrd@users.noreply.github.com> Date: Fri, 8 Nov 2019 22:52:47 +0100 Subject: Update docstring to use asterisks when referring to argument names Co-Authored-By: Kyle Stanley --- tests/bot/rules/test_links.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bot/rules/test_links.py b/tests/bot/rules/test_links.py index 40336beb0..be832843b 100644 --- a/tests/bot/rules/test_links.py +++ b/tests/bot/rules/test_links.py @@ -18,7 +18,7 @@ class Case(NamedTuple): def msg(author: str, total_links: int) -> FakeMessage: - """Makes a message with `total_links` links.""" + """Makes a message with *total_links* links.""" content = " ".join(["https://pydis.com"] * total_links) return FakeMessage(author=author, content=content) -- cgit v1.2.3 From 01ab4ad37dc68f38dd0fd15487dbff9bbd58c24e Mon Sep 17 00:00:00 2001 From: Derek Date: Sat, 9 Nov 2019 20:08:08 -0500 Subject: Forward user/role pings in checkpoint to mod-alerts [kaizen] limit on_message listener to verification channel --- bot/cogs/verification.py | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/bot/cogs/verification.py b/bot/cogs/verification.py index 3d85edae6..cd4311916 100644 --- a/bot/cogs/verification.py +++ b/bot/cogs/verification.py @@ -1,12 +1,16 @@ import logging from datetime import datetime -from discord import Message, NotFound, Object +from discord import Colour, Message, NotFound, Object from discord.ext import tasks from discord.ext.commands import Bot, Cog, Context, command from bot.cogs.moderation import ModLog -from bot.constants import Bot as BotConfig, Channels, Event, Roles +from bot.constants import ( + Bot as BotConfig, + Channels, Colours, Event, + Filter, Icons, Roles +) from bot.decorators import InChannelCheckFailure, in_channel, without_role log = logging.getLogger(__name__) @@ -53,6 +57,34 @@ class Verification(Cog): if message.author.bot: return # They're a bot, ignore + if message.channel.id != Channels.verification: + return # Only listen for #checkpoint messages + + # if a user mentions a role or guild member + # alert the mods in mod-alerts channel + if message.mentions or message.role_mentions: + log.debug( + f"{message.author} mentioned one or more users " + f"and/or roles in {message.channel.name}" + ) + + embed_text = ( + f"{message.author.mention} sent a message in " + f"{message.channel.mention} that contained user and/or role mentions." + f"\n\n**Original message:**\n>>> {message.content}" + ) + + # Send pretty mod log embed to mod-alerts + await self.mod_log.send_log_message( + icon_url=Icons.filtering, + colour=Colour(Colours.soft_red), + title=f"User/Role mentioned in {message.channel.name}", + text=embed_text, + thumbnail=message.author.avatar_url_as(static_format="png"), + channel_id=Channels.mod_alerts, + ping_everyone=Filter.ping_everyone, + ) + ctx = await self.bot.get_context(message) # type: Context if ctx.command is not None and ctx.command.name == "accept": -- cgit v1.2.3 From 0425e6c49ecf091871a06762a064755ea3dda04c Mon Sep 17 00:00:00 2001 From: Derek Date: Sat, 9 Nov 2019 21:07:11 -0500 Subject: [kaizen] Remove now duplicate channel check Unindent subsequent lines after check --- bot/cogs/verification.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/bot/cogs/verification.py b/bot/cogs/verification.py index cd4311916..b5e8d4357 100644 --- a/bot/cogs/verification.py +++ b/bot/cogs/verification.py @@ -90,27 +90,26 @@ class Verification(Cog): if ctx.command is not None and ctx.command.name == "accept": return # They used the accept command - if ctx.channel.id == Channels.verification: # We're in the verification channel - for role in ctx.author.roles: - if role.id == Roles.verified: - log.warning(f"{ctx.author} posted '{ctx.message.content}' " - "in the verification channel, but is already verified.") - return # They're already verified - - log.debug(f"{ctx.author} posted '{ctx.message.content}' in the verification " - "channel. We are providing instructions how to verify.") - await ctx.send( - f"{ctx.author.mention} Please type `!accept` to verify that you accept our rules, " - f"and gain access to the rest of the server.", - delete_after=20 - ) + for role in ctx.author.roles: + if role.id == Roles.verified: + log.warning(f"{ctx.author} posted '{ctx.message.content}' " + "in the verification channel, but is already verified.") + return # They're already verified + + log.debug(f"{ctx.author} posted '{ctx.message.content}' in the verification " + "channel. We are providing instructions how to verify.") + await ctx.send( + f"{ctx.author.mention} Please type `!accept` to verify that you accept our rules, " + f"and gain access to the rest of the server.", + delete_after=20 + ) - log.trace(f"Deleting the message posted by {ctx.author}") + log.trace(f"Deleting the message posted by {ctx.author}") - try: - await ctx.message.delete() - except NotFound: - log.trace("No message found, it must have been deleted by another bot.") + try: + await ctx.message.delete() + except NotFound: + log.trace("No message found, it must have been deleted by another bot.") @command(name='accept', aliases=('verify', 'verified', 'accepted'), hidden=True) @without_role(Roles.verified) -- cgit v1.2.3