diff options
-rw-r--r-- | bot/cogs/cogs.py | 8 | ||||
-rw-r--r-- | bot/cogs/filtering.py | 2 | ||||
-rw-r--r-- | bot/cogs/logging.py | 4 | ||||
-rw-r--r-- | bot/cogs/moderation.py | 2 | ||||
-rw-r--r-- | bot/cogs/site.py | 15 | ||||
-rw-r--r-- | bot/cogs/superstarify/__init__.py | 2 | ||||
-rw-r--r-- | bot/cogs/verification.py | 4 | ||||
-rw-r--r-- | bot/constants.py | 2 | ||||
-rw-r--r-- | config-default.yml | 4 | ||||
-rw-r--r-- | tests/cogs/test_token_remover.py | 133 | ||||
-rw-r--r-- | tests/helpers.py | 10 | ||||
-rw-r--r-- | tox.ini | 2 |
12 files changed, 167 insertions, 21 deletions
diff --git a/bot/cogs/cogs.py b/bot/cogs/cogs.py index ebdbf5ad8..7283aae6d 100644 --- a/bot/cogs/cogs.py +++ b/bot/cogs/cogs.py @@ -60,7 +60,7 @@ class Cogs: embed.set_author( name="Python Bot (Cogs)", - url=URLs.gitlab_bot_repo, + url=URLs.github_bot_repo, icon_url=URLs.bot_avatar ) @@ -113,7 +113,7 @@ class Cogs: embed.set_author( name="Python Bot (Cogs)", - url=URLs.gitlab_bot_repo, + url=URLs.github_bot_repo, icon_url=URLs.bot_avatar ) @@ -168,7 +168,7 @@ class Cogs: embed.set_author( name="Python Bot (Cogs)", - url=URLs.gitlab_bot_repo, + url=URLs.github_bot_repo, icon_url=URLs.bot_avatar ) @@ -269,7 +269,7 @@ class Cogs: embed.colour = Colour.blurple() embed.set_author( name="Python Bot (Cogs)", - url=URLs.gitlab_bot_repo, + url=URLs.github_bot_repo, icon_url=URLs.bot_avatar ) diff --git a/bot/cogs/filtering.py b/bot/cogs/filtering.py index 418297fc4..77f6eece5 100644 --- a/bot/cogs/filtering.py +++ b/bot/cogs/filtering.py @@ -59,7 +59,7 @@ class Filtering: "user_notification": Filter.notify_user_invites, "notification_msg": ( f"Per Rule 10, your invite link has been removed. {_staff_mistake_str}\n\n" - r"Our server rules can be found here: <https://pythondiscord.com/about/rules>" + r"Our server rules can be found here: <https://pythondiscord.com/pages/rules>" ) }, "filter_domains": { diff --git a/bot/cogs/logging.py b/bot/cogs/logging.py index 6b8462f3b..b31db60d9 100644 --- a/bot/cogs/logging.py +++ b/bot/cogs/logging.py @@ -23,8 +23,8 @@ class Logging: embed = Embed(description="Connected!") embed.set_author( name="Python Bot", - url="https://gitlab.com/discord-python/projects/bot", - icon_url="https://gitlab.com/python-discord/branding/raw/master/logos/logo_circle/logo_circle.png" + url="https://github.com/python-discord/bot", + icon_url="https://github.com/python-discord/branding/blob/master/logos/logo_circle/logo_circle.png" ) if not DEBUG_MODE: diff --git a/bot/cogs/moderation.py b/bot/cogs/moderation.py index fb791c933..532a44f4d 100644 --- a/bot/cogs/moderation.py +++ b/bot/cogs/moderation.py @@ -28,7 +28,7 @@ INFRACTION_ICONS = { "Kick": Icons.sign_out, "Ban": Icons.user_ban } -RULES_URL = "https://pythondiscord.com/about/rules" +RULES_URL = "https://pythondiscord.com/pages/rules" APPEALABLE_INFRACTIONS = ("Ban", "Mute") diff --git a/bot/cogs/site.py b/bot/cogs/site.py index b5e63fb41..b540827bf 100644 --- a/bot/cogs/site.py +++ b/bot/cogs/site.py @@ -46,15 +46,18 @@ class Site: async def site_resources(self, ctx: Context): """Info about the site's Resources page.""" - url = f"{PAGES_URL}/resources" + learning_url = f"{PAGES_URL}/resources" + tools_url = f"{PAGES_URL}/tools" - embed = Embed(title="Resources") - embed.set_footer(text=url) + embed = Embed(title="Resources & Tools") + embed.set_footer(text=f"{learning_url} | {tools_url}") embed.colour = Colour.blurple() embed.description = ( - f"The [Resources page]({url}) on our website contains a " + f"The [Resources page]({learning_url}) on our website contains a " "list of hand-selected goodies that we regularly recommend " - "to both beginners and experts." + f"to both beginners and experts. The [Tools page]({tools_url}) " + "contains a couple of the most popular tools for programming in " + "Python." ) await ctx.send(embed=embed) @@ -111,7 +114,7 @@ class Site: # Rules were not submitted. Return the default description. rules_embed.description = ( "The rules and guidelines that apply to this community can be found on" - " our [rules page](https://pythondiscord.com/about/rules). We expect" + f" our [rules page]({PAGES_URL}/rules). We expect" " all members of the community to have read and understood these." ) diff --git a/bot/cogs/superstarify/__init__.py b/bot/cogs/superstarify/__init__.py index cccd91304..b2e31db3e 100644 --- a/bot/cogs/superstarify/__init__.py +++ b/bot/cogs/superstarify/__init__.py @@ -15,7 +15,7 @@ from bot.decorators import with_role from bot.utils.moderation import post_infraction log = logging.getLogger(__name__) -NICKNAME_POLICY_URL = "https://pythondiscord.com/about/rules#nickname-policy" +NICKNAME_POLICY_URL = "https://pythondiscord.com/pages/rules/#wiki-toc-nickname-policy" class Superstarify: diff --git a/bot/cogs/verification.py b/bot/cogs/verification.py index 6b42c9213..efbcda166 100644 --- a/bot/cogs/verification.py +++ b/bot/cogs/verification.py @@ -14,8 +14,8 @@ Hello! Welcome to the server, and thanks for verifying yourself! For your records, these are the documents you accepted: -`1)` Our rules, here: <https://pythondiscord.com/about/rules> -`2)` Our privacy policy, here: <https://pythondiscord.com/about/privacy> - you can find information on how to have \ +`1)` Our rules, here: <https://pythondiscord.com/pages/rules> +`2)` Our privacy policy, here: <https://pythondiscord.com/pages/privacy> - you can find information on how to have \ your information removed here as well. Feel free to review them at any point! diff --git a/bot/constants.py b/bot/constants.py index 4e14a85a8..d5b73bd1d 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -412,7 +412,7 @@ class URLs(metaclass=YAMLGetter): # Misc endpoints bot_avatar: str deploy: str - gitlab_bot_repo: str + github_bot_repo: str status: str # Site endpoints diff --git a/config-default.yml b/config-default.yml index c9fc3b954..fd83e69a4 100644 --- a/config-default.yml +++ b/config-default.yml @@ -95,7 +95,7 @@ guild: bot: 267659945086812160 checkpoint_test: 422077681434099723 defcon: 464469101889454091 - devlog: &DEVLOG 409308876241108992 + devlog: &DEVLOG 622895325144940554 devtest: &DEVTEST 414574275865870337 help_0: 303906576991780866 help_1: 303906556754395136 @@ -273,7 +273,7 @@ urls: # Misc URLs bot_avatar: "https://raw.githubusercontent.com/discord-python/branding/master/logos/logo_circle/logo_circle.png" - gitlab_bot_repo: "https://gitlab.com/python-discord/projects/bot" + github_bot_repo: "https://github.com/python-discord/bot" anti_spam: # Clean messages that violate a rule. diff --git a/tests/cogs/test_token_remover.py b/tests/cogs/test_token_remover.py new file mode 100644 index 000000000..9d46b3a05 --- /dev/null +++ b/tests/cogs/test_token_remover.py @@ -0,0 +1,133 @@ +import asyncio +from unittest.mock import MagicMock + +import pytest +from discord import Colour + +from bot.cogs.token_remover import ( + DELETION_MESSAGE_TEMPLATE, + TokenRemover, + setup as setup_cog, +) +from bot.constants import Channels, Colours, Event, Icons +from tests.helpers import AsyncMock + + +def token_remover(): + bot = MagicMock() + bot.get_cog.return_value = MagicMock() + bot.get_cog.return_value.send_log_message = AsyncMock() + return TokenRemover(bot=bot) + + +def message(): + message = MagicMock() + message.author.__str__.return_value = 'lemon' + message.author.bot = False + message.author.avatar_url_as.return_value = 'picture-lemon.png' + message.author.id = 42 + message.author.mention = '@lemon' + message.channel.send = AsyncMock() + message.channel.mention = '#lemonade-stand' + message.content = '' + message.delete = AsyncMock() + message.id = 555 + return message + + + ('content', 'expected'), + ( + ('MTIz', True), # 123 + ('YWJj', False), # abc + ) +) +def test_is_valid_user_id(content: str, expected: bool): + assert TokenRemover.is_valid_user_id(content) is expected + + + ('content', 'expected'), + ( + ('DN9r_A', True), # stolen from dapi, thanks to the author of the 'token' tag! + ('MTIz', False), # 123 + ) +) +def test_is_valid_timestamp(content: str, expected: bool): + assert TokenRemover.is_valid_timestamp(content) is expected + + +def test_mod_log_property(token_remover): + token_remover.bot.get_cog.return_value = 'lemon' + assert token_remover.mod_log == 'lemon' + token_remover.bot.get_cog.assert_called_once_with('ModLog') + + +def test_ignores_bot_messages(token_remover, message): + message.author.bot = True + coroutine = token_remover.on_message(message) + assert asyncio.run(coroutine) is None + + [email protected]('content', ('', 'lemon wins')) +def test_ignores_messages_without_tokens(token_remover, message, content): + message.content = content + coroutine = token_remover.on_message(message) + assert asyncio.run(coroutine) is None + + [email protected]('content', ('foo.bar.baz', 'x.y.')) +def test_ignores_invalid_tokens(token_remover, message, content): + message.content = content + coroutine = token_remover.on_message(message) + assert asyncio.run(coroutine) is None + + + 'content, censored_token', + ( + ('MTIz.DN9R_A.xyz', 'MTIz.DN9R_A.xxx'), + ) +) +def test_censors_valid_tokens( + token_remover, message, content, censored_token, caplog +): + message.content = content + coroutine = token_remover.on_message(message) + assert asyncio.run(coroutine) is None # still no rval + + # asyncio logs some stuff about its reactor, discard it + [_, record] = caplog.records + assert record.message == ( + "Censored a seemingly valid token sent by lemon (`42`) in #lemonade-stand, " + f"token was `{censored_token}`" + ) + + message.delete.assert_called_once_with() + message.channel.send.assert_called_once_with( + DELETION_MESSAGE_TEMPLATE.format(mention='@lemon') + ) + token_remover.bot.get_cog.assert_called_with('ModLog') + message.author.avatar_url_as.assert_called_once_with(static_format='png') + + mod_log = token_remover.bot.get_cog.return_value + mod_log.ignore.assert_called_once_with(Event.message_delete, message.id) + mod_log.send_log_message.assert_called_once_with( + icon_url=Icons.token_removed, + colour=Colour(Colours.soft_red), + title="Token removed!", + text=record.message, + thumbnail='picture-lemon.png', + channel_id=Channels.mod_alerts + ) + + +def test_setup(caplog): + bot = MagicMock() + setup_cog(bot) + [record] = caplog.records + + bot.add_cog.assert_called_once() + assert record.message == "Cog loaded: TokenRemover" diff --git a/tests/helpers.py b/tests/helpers.py new file mode 100644 index 000000000..57c6fcc1a --- /dev/null +++ b/tests/helpers.py @@ -0,0 +1,10 @@ +from unittest.mock import MagicMock + + +__all__ = ('AsyncMock',) + + +# TODO: Remove me on 3.8 +class AsyncMock(MagicMock): + async def __call__(self, *args, **kwargs): + return super(AsyncMock, self).__call__(*args, **kwargs) @@ -1,6 +1,6 @@ [flake8] max-line-length=120 -application_import_names=bot +application_import_names=bot,tests exclude=.cache,.venv ignore=B311,W503,E226,S311,T000 import-order-style=pycharm |