Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uses settings to control ephemeral state. #120

Merged
merged 11 commits into from
Mar 2, 2022
2 changes: 2 additions & 0 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,6 @@ Some known limitations of currently supported platforms:
- No table functionality in cards (blocks). The `ColumnSet` card layout feature allows for wrapping content across
multiple columns, but does not provide for any alignment across columns, so it's not suitable for tables.

## Settings

The setting of `send_all_messages_private` within the configuration applied within the Nautobot config is used to send all messages as private messages. The messages will be sent in private when this is set to `True`. The default setting is `False`, which is the behavior for several message settings.
jvanderaa marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 4 additions & 0 deletions nautobot_chatops/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class NautobotChatOpsConfig(PluginConfig):
# Mattermost-specific settings
"mattermost_api_token": None,
"mattermost_url": None,
# As requested on https://github.com/nautobot/nautobot-plugin-chatops/issues/114 this setting is used for
# sending all messages as an ephemeral message, meaning only the person interacting with the bot will see the
# responses.
"send_all_messages_private": False,
}

max_version = "1.999"
Expand Down
9 changes: 7 additions & 2 deletions nautobot_chatops/dispatchers/adaptive_cards.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Dispatcher subclass for chat platforms that use Adaptive Cards (https://adaptivecards.io/)."""

from .base import Dispatcher

# pylint: disable=abstract-method
Expand Down Expand Up @@ -121,7 +120,13 @@ def multi_input_dialog(self, command, sub_command, dialog_title, dialog_list):
],
}
blocks.append(buttons)
return self.send_blocks(blocks, callback_id=callback_id, modal=True, ephemeral=False, title=dialog_title)
return self.send_blocks(
blocks,
callback_id=callback_id,
modal=True,
ephemeral=False,
title=dialog_title,
)
jvanderaa marked this conversation as resolved.
Show resolved Hide resolved

def send_warning(self, message):
"""Send a warning message to the user/channel specified by the context."""
Expand Down
36 changes: 34 additions & 2 deletions nautobot_chatops/dispatchers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,23 @@ def ask_permission_to_send_image(self, filename, action_id):

# Send various content to the user or channel

def send_markdown(self, message, ephemeral=False):
def send_markdown(self, message, ephemeral=None):
"""Send a Markdown-formatted text message to the user/channel specified by the context."""
if ephemeral is None:
ephemeral = settings.PLUGINS_CONFIG["nautobot_chatops"]["send_all_messages_private"]
raise NotImplementedError

def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=False, title=None):
def send_blocks(
self,
blocks,
callback_id=None,
modal=False,
ephemeral=None,
title=None,
):
"""Send a series of formatting blocks to the user/channel specified by the context."""
if ephemeral is None:
ephemeral = settings.PLUGINS_CONFIG["nautobot_chatops"]["send_all_messages_private"]
raise NotImplementedError

def send_snippet(self, text, title=None):
Expand Down Expand Up @@ -327,3 +338,24 @@ def select_element(self, action_id, choices, default=(None, None), confirm=False
def text_element(self, text):
"""Construct a simple plaintext element."""
raise NotImplementedError

@staticmethod
def split_messages(text_string: str, max_message_size: int) -> list:
jvanderaa marked this conversation as resolved.
Show resolved Hide resolved
"""Method to split a message into smaller messages.

Args:
text_string (str): Text string that should be split
max_message_size (int): Maximum size for a message
"""
return_list = [""]

for line in text_string.splitlines():
# len(line) + 2 to account for a new line character in the character line
# Check to see if the line length of the last item in the list is longer than the max message size
# Once it would be larger than the max size, then start the next line.
if (len(line) + 2) + len(return_list[-1]) < max_message_size:
return_list[-1] += f"{line}\n"
else:
return_list.append(f"{line}\n")

return return_list
16 changes: 12 additions & 4 deletions nautobot_chatops/dispatchers/mattermost.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,10 @@ def command_response_header(self, command, subcommand, args, description="inform
# Send various content to the user or channel

@BACKEND_ACTION_MARKDOWN.time()
def send_markdown(self, message, ephemeral=False):
def send_markdown(self, message, ephemeral=None):
"""Send a Markdown-formatted text message to the user/channel specified by the context."""
if ephemeral is None:
ephemeral = settings.PLUGINS_CONFIG["nautobot_chatops"]["send_all_messages_private"]
try:
if ephemeral:
self.mm_client.chat_post_ephemeral(
Expand All @@ -360,7 +362,7 @@ def send_markdown(self, message, ephemeral=False):

# pylint: disable=arguments-differ
@BACKEND_ACTION_BLOCKS.time()
def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=False, title="Your attention please!"):
def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=None, title="Your attention please!"):
"""Send a series of formatting blocks to the user/channel specified by the context.

Args:
Expand All @@ -370,6 +372,8 @@ def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=False, ti
ephemeral (bool): Whether to send this as an ephemeral message (only visible to the targeted user).
title (str): Title to include on a modal dialog.
"""
if ephemeral is None:
ephemeral = settings.PLUGINS_CONFIG["nautobot_chatops"]["send_all_messages_private"]
logger.info("Sending blocks: %s", json.dumps(blocks, indent=2))
try:
if modal:
Expand Down Expand Up @@ -403,11 +407,15 @@ def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=False, ti
self.send_exception(mm_error)

@BACKEND_ACTION_SNIPPET.time()
def send_snippet(self, text, title=None):
def send_snippet(self, text, title=None, ephemeral=None):
jvanderaa marked this conversation as resolved.
Show resolved Hide resolved
"""Send a longer chunk of text as a file snippet."""
channel = [self.context.get("channel_id")]
logger.info("Sending snippet to %s: %s", channel, text)
self.mm_client.chat_post_message(channel_id=self.context.get("channel_id"), snippet=text)
if ephemeral:
for msg in self.split_messages(text, 16383):
jvanderaa marked this conversation as resolved.
Show resolved Hide resolved
self.mm_client.chat_post_ephemeral(channel_id=self.context.get("channel_id"), message=msg)
else:
self.mm_client.chat_post_message(channel_id=self.context.get("channel_id"), snippet=text)

def send_image(self, image_path):
"""Send an image as a file upload."""
Expand Down
6 changes: 3 additions & 3 deletions nautobot_chatops/dispatchers/ms_teams.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ def ask_permission_to_send_image(self, filename, action_id):
)

@BACKEND_ACTION_MARKDOWN.time()
def send_markdown(self, message, ephemeral=False):
def send_markdown(self, message, ephemeral=None):
"""Send a markdown-formatted text message to the user/channel specified by the context."""
self._send({"text": message, "textFormat": "markdown"})

@BACKEND_ACTION_BLOCKS.time()
def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=False, title=None):
def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=None, title=None):
"""Send a series of formatting blocks to the user/channel specified by the context."""
if title and title not in str(blocks[0]):
blocks.insert(0, self.markdown_element(self.bold(title)))
Expand All @@ -170,7 +170,7 @@ def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=False, ti
)

@BACKEND_ACTION_SNIPPET.time()
def send_snippet(self, text, title=None):
def send_snippet(self, text, title=None, ephemeral=None):
"""Send a longer chunk of text as a snippet or file attachment."""
self.send_markdown(f"```\n{text}\n```")

Expand Down
27 changes: 23 additions & 4 deletions nautobot_chatops/dispatchers/slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,12 @@ def command_response_header(self, command, subcommand, args, description="inform
# Send various content to the user or channel

@BACKEND_ACTION_MARKDOWN.time()
def send_markdown(self, message, ephemeral=False):
def send_markdown(self, message, ephemeral=None):
"""Send a Markdown-formatted text message to the user/channel specified by the context."""
try:
if ephemeral is None:
ephemeral = settings.PLUGINS_CONFIG["nautobot_chatops"]["send_all_messages_private"]

if ephemeral:
self.slack_client.chat_postEphemeral(
channel=self.context.get("channel_id"),
Expand All @@ -156,7 +159,7 @@ def send_markdown(self, message, ephemeral=False):

# pylint: disable=arguments-differ
@BACKEND_ACTION_BLOCKS.time()
def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=False, title="Your attention please!"):
def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=None, title="Your attention please!"):
"""Send a series of formatting blocks to the user/channel specified by the context.

Slack distinguishes between simple inline interactive elements and modal dialogs. Modals can contain multiple
Expand All @@ -171,6 +174,8 @@ def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=False, ti
title (str): Title to include on a modal dialog.
"""
logger.info("Sending blocks: %s", json.dumps(blocks, indent=2))
if ephemeral is None:
ephemeral = settings.PLUGINS_CONFIG["nautobot_chatops"]["send_all_messages_private"]
try:
if modal:
if not callback_id:
Expand Down Expand Up @@ -208,16 +213,30 @@ def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=False, ti
self.send_exception(slack_error)

@BACKEND_ACTION_SNIPPET.time()
def send_snippet(self, text, title=None):
def send_snippet(self, text, title=None, ephemeral=None):
"""Send a longer chunk of text as a file snippet."""
if ephemeral is None:
ephemeral = settings.PLUGINS_CONFIG["nautobot_chatops"]["send_all_messages_private"]

if self.context.get("channel_name") == "directmessage":
channels = [self.context.get("user_id")]
else:
channels = [self.context.get("channel_id")]
channels = ",".join(channels)
logger.info("Sending snippet to %s: %s", channels, text)
try:
self.slack_client.files_upload(channels=channels, content=text, title=title)
# Check for the length of the file if the setup is meant to be a private message
if ephemeral:
message_list = self.split_messages(text, 40000)
jvanderaa marked this conversation as resolved.
Show resolved Hide resolved
for msg in message_list:
self.slack_client.chat_postEphemeral(
channel=self.context.get("channel_id"),
user=self.context.get("user_id"),
text="test",
jvanderaa marked this conversation as resolved.
Show resolved Hide resolved
blocks=[{"type": "section", "text": {"type": "mrkdwn", "text": msg}}],
)
jvanderaa marked this conversation as resolved.
Show resolved Hide resolved
else:
self.slack_client.files_upload(channels=channels, content=text, title=title)
jvanderaa marked this conversation as resolved.
Show resolved Hide resolved
except SlackClientError as slack_error:
self.send_exception(slack_error)

Expand Down
6 changes: 3 additions & 3 deletions nautobot_chatops/dispatchers/webex.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,12 @@ def platform_lookup(cls, item_type, item_name):
return None

@BACKEND_ACTION_MARKDOWN.time()
def send_markdown(self, message, ephemeral=False):
def send_markdown(self, message, ephemeral=None):
"""Send a markdown-formatted text message to the user/channel specified by the context."""
self.client.messages.create(roomId=self.context["channel_id"], markdown=message)

@BACKEND_ACTION_BLOCKS.time()
def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=False, title=None):
def send_blocks(self, blocks, callback_id=None, modal=False, ephemeral=None, title=None):
"""Send a series of formatting blocks to the user/channel specified by the context."""
if title and title not in str(blocks[0]):
blocks.insert(0, self.markdown_element(self.bold(title)))
Expand All @@ -119,7 +119,7 @@ def send_image(self, image_path):
self.client.messages.create(roomId=self.context["channel_id"], files=[image_path])

@BACKEND_ACTION_SNIPPET.time()
def send_snippet(self, text, title=None):
def send_snippet(self, text, title=None, ephemeral=None):
"""Send a longer chunk of text as a file snippet."""
return self.send_markdown(f"```\n{text}\n```")

Expand Down
9 changes: 7 additions & 2 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,17 @@ def is_truthy(arg):
namespace.configure(
{
"nautobot_chatops": {
"nautobot_ver": "1.0.1",
"nautobot_ver": "1.1.6",
"project_name": "nautobot-chatops",
"python_ver": "3.6",
"local": False,
"compose_dir": os.path.join(os.path.dirname(__file__), "development"),
"compose_files": ["docker-compose.requirements.yml", "docker-compose.base.yml", "docker-compose.dev.yml"],
"compose_files": [
"docker-compose.requirements.yml",
# "docker-compose.celery.yml",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If 1.1 is now the default nautobot version, don't we need to include celery by default?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be. I'm going to do the update to nautobot dev environment in a separate PR. This is a better method to have the Celery components commented out but in the code. It is just easier then to get it up and running.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just an easier method to handle converting over to using 1.1 or later. When Nautobot 1.3 comes out we will make the updates to go to Python3.7 and update to the newer methods.

"docker-compose.base.yml",
"docker-compose.dev.yml",
],
}
}
)
Expand Down