From 7f9d1b83487614cf078f5506dec28563b00a55b0 Mon Sep 17 00:00:00 2001 From: Steven <44085060+aconitumnapellus@users.noreply.github.com> Date: Fri, 25 Feb 2022 13:44:40 +0100 Subject: [PATCH 01/15] SILENCE --- mmpy_bot/function.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/mmpy_bot/function.py b/mmpy_bot/function.py index 7f6f6157..c4226e79 100644 --- a/mmpy_bot/function.py +++ b/mmpy_bot/function.py @@ -124,9 +124,6 @@ def __call__(self, message: Message, *args): return return_value if self.allowed_users and message.sender_name not in self.allowed_users: - self.plugin.driver.reply_to( - message, "You do not have permission to perform this action!" - ) return return_value if self.allowed_channels and message.channel_name not in self.allowed_channels: From c91b0a868b2bb716b2745b53ee5f40a7842f95b6 Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Thu, 4 Aug 2022 14:16:21 +0200 Subject: [PATCH 02/15] add no reply parameter --- mmpy_bot/function.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/mmpy_bot/function.py b/mmpy_bot/function.py index 15279c5f..ade23b84 100644 --- a/mmpy_bot/function.py +++ b/mmpy_bot/function.py @@ -63,6 +63,7 @@ def __init__( *args, direct_only: bool = False, needs_mention: bool = False, + no_reply: bool = False, allowed_users: Optional[Sequence[str]] = None, allowed_channels: Optional[Sequence[str]] = None, **kwargs, @@ -72,6 +73,7 @@ def __init__( self.is_click_function = isinstance(self.function, click.Command) self.direct_only = direct_only self.needs_mention = needs_mention + self.no_reply = no_reply if allowed_users is None: self.allowed_users = [] @@ -130,9 +132,10 @@ def __call__(self, message: Message, *args): return return_value if self.allowed_channels and message.channel_name not in self.allowed_channels: - self.plugin.driver.reply_to( - message, "You do not have permission to perform this action!" - ) + if self.no_reply: + self.plugin.driver.reply_to( + message, "You do not have permission to perform this action!" + ) return return_value if self.is_click_function: @@ -161,6 +164,7 @@ def get_help_string(self): self.direct_only, self.allowed_users, self.allowed_channels, + self.no_reply ] ): # Print some information describing the usage settings. @@ -179,6 +183,9 @@ def get_help_string(self): if self.allowed_channels: string += f"{spaces(4)}- Restricted to certain channels.\n" + if self.no_reply: + string += f"{spaces(4)}- If it should reply to a non privileged user / in a non privileged channel.\n" + return string @@ -190,6 +197,7 @@ def listen_to( needs_mention=False, allowed_users=None, allowed_channels=None, + no_reply=False, **metadata, ): """Wrap the given function in a MessageFunction class so we can register some @@ -224,6 +232,7 @@ def wrapped_func(func): needs_mention=needs_mention, allowed_users=allowed_users, allowed_channels=allowed_channels, + no_reply=no_reply, **metadata, ) From a2b75dac25b6238d90b7bfd78fcab08d1c66a0ca Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Thu, 4 Aug 2022 14:17:09 +0200 Subject: [PATCH 03/15] make channel name configurable --- tests/unit_tests/event_handler_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit_tests/event_handler_test.py b/tests/unit_tests/event_handler_test.py index e7f7c6f3..7959eedb 100644 --- a/tests/unit_tests/event_handler_test.py +++ b/tests/unit_tests/event_handler_test.py @@ -13,13 +13,14 @@ def create_message( mentions=["qmw86q7qsjriura9jos75i4why"], channel_type="O", sender_name="betty", + channel_name="off-topic", ): return Message( { "event": "posted", "data": { "channel_display_name": "Off-Topic", - "channel_name": "off-topic", + "channel_name": channel_name, "channel_type": channel_type, "mentions": mentions, "post": { From 278025c6b7ab846e999524a49df65aaca48a02ad Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Thu, 4 Aug 2022 14:17:24 +0200 Subject: [PATCH 04/15] expose port instead of host net mode --- tests/integration_tests/docker-compose.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/integration_tests/docker-compose.yml b/tests/integration_tests/docker-compose.yml index 90bf83ed..111a3d88 100644 --- a/tests/integration_tests/docker-compose.yml +++ b/tests/integration_tests/docker-compose.yml @@ -5,6 +5,7 @@ services: container_name: "mattermost-bot-test" build: . command: ./mm/docker-entry.sh - network_mode: host + ports: + - 8065:8065 extra_hosts: - "dockerhost:127.0.0.1" From 564f8b2bcc6575fac3112ec903c072ed7d81a35a Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Thu, 4 Aug 2022 14:17:38 +0200 Subject: [PATCH 05/15] use newer version of pytype --- dev-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 059527e4..54414c8d 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -5,5 +5,5 @@ flake8==4.0.1 isort==5.10.1 pytest==7.1.2 pytest-xdist==2.5.0 -pytype==2021.10.18 +pytype==2022.4.15 snapshottest==0.6.0 From 0c1e0dadc53945d9f9fcd16a92ba7ec8be26b2e2 Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Thu, 4 Aug 2022 14:18:15 +0200 Subject: [PATCH 06/15] add a test for allowed_channels --- tests/unit_tests/function_test.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/unit_tests/function_test.py b/tests/unit_tests/function_test.py index 555cffe7..ec2a5267 100644 --- a/tests/unit_tests/function_test.py +++ b/tests/unit_tests/function_test.py @@ -188,6 +188,29 @@ def fake_reply(message, text): wrapped.assert_not_called() driver.reply_to.assert_called_once() + def test_allowed_channels(self): + wrapped = mock.create_autospec(example_listener) + wrapped.__qualname__ = "wrapped" + # Create a driver with a mocked reply function + driver = Driver() + + def fake_reply(message, text): + assert "you do not have permission" in text.lower() + + driver.reply_to = mock.Mock(wraps=fake_reply) + + f = listen_to("", allowed_channels=["off-topic"])(wrapped) + f.plugin = ExamplePlugin().initialize(driver) + + # This is fine, the names are not caps sensitive + f(create_message(channel_name="off-topic")) + wrapped.assert_called_once() + wrapped.reset_mock() + + # This is not fine, and we expect the fake reply to be called. + f(create_message(channel_name="town-square")) + wrapped.assert_not_called() + driver.reply_to.assert_called_once() def example_webhook_listener(self, event): # Used to copy the arg specs to mock.Mock functions. From 957a795e612073d269bd9da203ab28e35b5c5cb9 Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Thu, 4 Aug 2022 14:29:11 +0200 Subject: [PATCH 07/15] enable reply by default --- mmpy_bot/function.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmpy_bot/function.py b/mmpy_bot/function.py index ade23b84..94e843d2 100644 --- a/mmpy_bot/function.py +++ b/mmpy_bot/function.py @@ -132,7 +132,7 @@ def __call__(self, message: Message, *args): return return_value if self.allowed_channels and message.channel_name not in self.allowed_channels: - if self.no_reply: + if self.no_reply is False: self.plugin.driver.reply_to( message, "You do not have permission to perform this action!" ) From c44f624efe5c08e9be82001b1bc45af909821866 Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Thu, 4 Aug 2022 15:00:56 +0200 Subject: [PATCH 08/15] add back permission denied message --- mmpy_bot/function.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mmpy_bot/function.py b/mmpy_bot/function.py index 94e843d2..ca62efdc 100644 --- a/mmpy_bot/function.py +++ b/mmpy_bot/function.py @@ -129,6 +129,10 @@ def __call__(self, message: Message, *args): return return_value if self.allowed_users and message.sender_name not in self.allowed_users: + if self.no_reply is False: + self.plugin.driver.reply_to( + message, "You do not have permission to perform this action!" + ) return return_value if self.allowed_channels and message.channel_name not in self.allowed_channels: From d166e10d961860c18ea681bc9c979f94f5472550 Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Thu, 4 Aug 2022 15:28:22 +0200 Subject: [PATCH 09/15] add example for channel limitation --- mmpy_bot/plugins/example.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mmpy_bot/plugins/example.py b/mmpy_bot/plugins/example.py index 70485698..639e547b 100644 --- a/mmpy_bot/plugins/example.py +++ b/mmpy_bot/plugins/example.py @@ -19,6 +19,11 @@ async def users_access(self, message: Message): """Showcases a function with restricted access.""" self.driver.reply_to(message, "Access allowed!") + @listen_to("^offtopic_channel$", allowed_channels=["off-topic"]) + async def channels_access(self, message: Message): + """Showcases a function which can only be used in specific channels""" + self.driver.reply_to(message, "Access allowed!") + @listen_to("^busy|jobs$", re.IGNORECASE, needs_mention=True) async def busy_reply(self, message: Message): """Show the number of busy worker threads.""" From 46bd180dbaab787770c58fea9884555c1975b6c4 Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Thu, 4 Aug 2022 15:30:06 +0200 Subject: [PATCH 10/15] add unit test for no reply --- tests/unit_tests/function_test.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/unit_tests/function_test.py b/tests/unit_tests/function_test.py index ec2a5267..75410405 100644 --- a/tests/unit_tests/function_test.py +++ b/tests/unit_tests/function_test.py @@ -212,6 +212,31 @@ def fake_reply(message, text): wrapped.assert_not_called() driver.reply_to.assert_called_once() + def test_allowed_channels_no_reply(self): + wrapped = mock.create_autospec(example_listener) + wrapped.__qualname__ = "wrapped" + # Create a driver with a mocked reply function + driver = Driver() + + def fake_reply(message, text): + assert "you do not have permission" in text.lower() + + driver.reply_to = mock.Mock(wraps=fake_reply) + + f = listen_to("", allowed_channels=["off-topic"], no_reply=True)(wrapped) + f.plugin = ExamplePlugin().initialize(driver) + + # This is fine, the names are not caps sensitive + f(create_message(channel_name="off-topic")) + wrapped.assert_called_once() + wrapped.reset_mock() + + # This is not fine, and we expect the fake reply not to be called. + f(create_message(channel_name="town-square")) + wrapped.assert_not_called() + driver.reply_to.assert_not_called() + + def example_webhook_listener(self, event): # Used to copy the arg specs to mock.Mock functions. pass From cae94e1bf95c72d53fccee27fc639971ff30c6fc Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Fri, 5 Aug 2022 12:14:39 +0200 Subject: [PATCH 11/15] reformat with black --- mmpy_bot/function.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmpy_bot/function.py b/mmpy_bot/function.py index ca62efdc..2432a331 100644 --- a/mmpy_bot/function.py +++ b/mmpy_bot/function.py @@ -168,7 +168,7 @@ def get_help_string(self): self.direct_only, self.allowed_users, self.allowed_channels, - self.no_reply + self.no_reply, ] ): # Print some information describing the usage settings. From eed36ad4152d77dce3ca9f5d87dcb60a74b4a81a Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Fri, 5 Aug 2022 12:19:42 +0200 Subject: [PATCH 12/15] i need to please docformatter --- mmpy_bot/plugins/example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmpy_bot/plugins/example.py b/mmpy_bot/plugins/example.py index 639e547b..ee1f10a4 100644 --- a/mmpy_bot/plugins/example.py +++ b/mmpy_bot/plugins/example.py @@ -21,7 +21,7 @@ async def users_access(self, message: Message): @listen_to("^offtopic_channel$", allowed_channels=["off-topic"]) async def channels_access(self, message: Message): - """Showcases a function which can only be used in specific channels""" + """Showcases a function which can only be used in specific channels.""" self.driver.reply_to(message, "Access allowed!") @listen_to("^busy|jobs$", re.IGNORECASE, needs_mention=True) From 7a6592262cc2bc15263fc867618a0d840f8a15dd Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Fri, 5 Aug 2022 12:25:12 +0200 Subject: [PATCH 13/15] Revert "use newer version of pytype" This reverts commit 564f8b2bcc6575fac3112ec903c072ed7d81a35a. --- dev-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 54414c8d..059527e4 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -5,5 +5,5 @@ flake8==4.0.1 isort==5.10.1 pytest==7.1.2 pytest-xdist==2.5.0 -pytype==2022.4.15 +pytype==2021.10.18 snapshottest==0.6.0 From e2bc4f7c44e6ce3f20ec47cb94d7d7e034025a13 Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Mon, 8 Aug 2022 10:44:54 +0200 Subject: [PATCH 14/15] good vibes only! (refactor) --- mmpy_bot/function.py | 16 ++++++++-------- tests/unit_tests/function_test.py | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mmpy_bot/function.py b/mmpy_bot/function.py index 2432a331..dee34035 100644 --- a/mmpy_bot/function.py +++ b/mmpy_bot/function.py @@ -63,7 +63,7 @@ def __init__( *args, direct_only: bool = False, needs_mention: bool = False, - no_reply: bool = False, + silence_fail_msg: bool = False, allowed_users: Optional[Sequence[str]] = None, allowed_channels: Optional[Sequence[str]] = None, **kwargs, @@ -73,7 +73,7 @@ def __init__( self.is_click_function = isinstance(self.function, click.Command) self.direct_only = direct_only self.needs_mention = needs_mention - self.no_reply = no_reply + self.silence_fail_msg = silence_fail_msg if allowed_users is None: self.allowed_users = [] @@ -129,14 +129,14 @@ def __call__(self, message: Message, *args): return return_value if self.allowed_users and message.sender_name not in self.allowed_users: - if self.no_reply is False: + if self.silence_fail_msg is False: self.plugin.driver.reply_to( message, "You do not have permission to perform this action!" ) return return_value if self.allowed_channels and message.channel_name not in self.allowed_channels: - if self.no_reply is False: + if self.silence_fail_msg is False: self.plugin.driver.reply_to( message, "You do not have permission to perform this action!" ) @@ -168,7 +168,7 @@ def get_help_string(self): self.direct_only, self.allowed_users, self.allowed_channels, - self.no_reply, + self.silence_fail_msg, ] ): # Print some information describing the usage settings. @@ -187,7 +187,7 @@ def get_help_string(self): if self.allowed_channels: string += f"{spaces(4)}- Restricted to certain channels.\n" - if self.no_reply: + if self.silence_fail_msg: string += f"{spaces(4)}- If it should reply to a non privileged user / in a non privileged channel.\n" return string @@ -201,7 +201,7 @@ def listen_to( needs_mention=False, allowed_users=None, allowed_channels=None, - no_reply=False, + silence_fail_msg=False, **metadata, ): """Wrap the given function in a MessageFunction class so we can register some @@ -236,7 +236,7 @@ def wrapped_func(func): needs_mention=needs_mention, allowed_users=allowed_users, allowed_channels=allowed_channels, - no_reply=no_reply, + silence_fail_msg=silence_fail_msg, **metadata, ) diff --git a/tests/unit_tests/function_test.py b/tests/unit_tests/function_test.py index 75410405..0e4b64d7 100644 --- a/tests/unit_tests/function_test.py +++ b/tests/unit_tests/function_test.py @@ -212,7 +212,7 @@ def fake_reply(message, text): wrapped.assert_not_called() driver.reply_to.assert_called_once() - def test_allowed_channels_no_reply(self): + def test_allowed_channels_silence_fail_msg(self): wrapped = mock.create_autospec(example_listener) wrapped.__qualname__ = "wrapped" # Create a driver with a mocked reply function @@ -223,7 +223,7 @@ def fake_reply(message, text): driver.reply_to = mock.Mock(wraps=fake_reply) - f = listen_to("", allowed_channels=["off-topic"], no_reply=True)(wrapped) + f = listen_to("", allowed_channels=["off-topic"], silence_fail_msg=True)(wrapped) f.plugin = ExamplePlugin().initialize(driver) # This is fine, the names are not caps sensitive From 6b94ada43dc017d87e5ad0f2a94f6f930b7d5813 Mon Sep 17 00:00:00 2001 From: aconitumnapellus <44085060+aconitumnapellus@users.noreply.github.com> Date: Mon, 8 Aug 2022 11:00:39 +0200 Subject: [PATCH 15/15] rerun black to please CI --- tests/unit_tests/function_test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/unit_tests/function_test.py b/tests/unit_tests/function_test.py index 0e4b64d7..3097251d 100644 --- a/tests/unit_tests/function_test.py +++ b/tests/unit_tests/function_test.py @@ -223,7 +223,9 @@ def fake_reply(message, text): driver.reply_to = mock.Mock(wraps=fake_reply) - f = listen_to("", allowed_channels=["off-topic"], silence_fail_msg=True)(wrapped) + f = listen_to("", allowed_channels=["off-topic"], silence_fail_msg=True)( + wrapped + ) f.plugin = ExamplePlugin().initialize(driver) # This is fine, the names are not caps sensitive