oncall-engine/engine/apps/slack/slack_formatter.py

108 lines
4.4 KiB
Python
Raw Permalink Normal View History

import re
import emoji
from slackviewer.formatter import SlackFormatter as SlackFormatterBase
class SlackFormatter(SlackFormatterBase):
_LINK_PAT = re.compile(r"<(https|http|mailto):[A-Za-z0-9_\.\-\/\?\,\=\#\:\@\& ]+\|[^>]+>")
def __init__(self, organization):
self.__ORGANIZATION = organization
self.channel_mention_format = "#{}"
self.user_mention_format = "@{}"
self.hyperlink_mention_format = '<a href="{url}">{title}</a>'
def format(self, message):
"""
Overriden original render_text method.
Now it is responsible only for formatting slack mentions, channel names, etc.
"""
if message is None:
return
message = message.replace("<!channel>", "@channel")
message = message.replace("<!channel|@channel>", "@channel")
message = message.replace("<!here>", "@here")
message = message.replace("<!here|@here>", "@here")
message = message.replace("<!everyone>", "@everyone")
message = message.replace("<!everyone|@everyone>", "@everyone")
Fix warnings when running backend tests (#2079) # What this PR does - update `make test` to always use `settings.ci-test`. Right now it will use whatever the value of `DJANGO_SETTINGS_MODULE` is in `./dev/.env.dev`, which causes ~45 tests to fail - Fix several Python warnings that we see when running the tests ```bash RemovedInDjango40Warning: The providing_args argument is deprecated. As it is purely documentational, it has no replacement. If you rely on this argument as documentation, you can move the text to a code comment or docstring. alert_create_signal = django.dispatch.Signal( ``` ```bash PytestCollectionWarning: cannot collect test class 'TestOnlyBackend' because it has a __init__ constructor (from: apps/api/tests/test_alert_receive_channel_template.py) class TestOnlyBackend(BaseMessagingBackend): ``` ```bash DeprecationWarning: The parameter 'use_aliases' in emoji.emojize() is deprecated and will be removed in version 2.0.0. Use language='alias' instead. To hide this warning, pin/downgrade the package to 'emoji~=1.6.3' return emoji.emojize(self.verbal_name, use_aliases=True) ``` ```bash DateTimeField CustomOnCallShift.start received a naive datetime (2023-06-01 12:53:12) while time zone support is active. warnings.warn("DateTimeField %s received a naive datetime (%s)" ``` ```bash apps/twilioapp/tests/test_phone_calls.py::test_resolve_by_phone /etc/app/apps/twilioapp/tests/test_phone_calls.py:173: DeprecationWarning: The 'text' argument to find()-type methods is deprecated. Use 'string' instead. content = BeautifulSoup(content, features="html.parser").findAll(text=True) ``` ```bash apps/twilioapp/tests/test_phone_calls.py::test_resolve_by_phone apps/twilioapp/tests/test_phone_calls.py::test_wrong_pressed_digit /usr/local/lib/python3.11/site-packages/bs4/builder/__init__.py:545: XMLParsedAsHTMLWarning: It looks like you're parsing an XML document using an HTML parser. If this really is an HTML document (maybe it's XHTML?), you can ignore or filter this warning. If it's XML, you should know that using an XML parser will be more reliable. To parse this document as XML, make sure you have the lxml package installed, and pass the keyword argument `features="xml"` into the BeautifulSoup constructor. ``` ```bash apps/twilioapp/tests/test_phone_calls.py::test_forbidden_requests /usr/local/lib/python3.11/site-packages/social_django/urls.py:15: RemovedInDjango40Warning: django.conf.urls.url() is deprecated in favor of django.urls.re_path(). url(r'^login/(?P<backend>[^/]+){0}$'.format(extra), views.auth, ``` ```bash apps/twilioapp/tests/test_phone_calls.py: 66 warnings /usr/local/lib/python3.11/site-packages/debug_toolbar/utils.py:255: DeprecationWarning: currentThread() is deprecated, use current_thread() instead thread = threading.currentThread() ``` ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
2023-06-06 20:38:00 +02:00
message = self.slack_to_accepted_emoji(message)
# Handle mentions of users, channels and bots (e.g "<@U0BM1CGQY|calvinchanubc> has joined the channel")
message = self._MENTION_PAT.sub(self._sub_annotated_mention, message)
# Handle links
message = self._LINK_PAT.sub(self._sub_hyperlink, message)
# Introduce unicode emoji
Fix warnings when running backend tests (#2079) # What this PR does - update `make test` to always use `settings.ci-test`. Right now it will use whatever the value of `DJANGO_SETTINGS_MODULE` is in `./dev/.env.dev`, which causes ~45 tests to fail - Fix several Python warnings that we see when running the tests ```bash RemovedInDjango40Warning: The providing_args argument is deprecated. As it is purely documentational, it has no replacement. If you rely on this argument as documentation, you can move the text to a code comment or docstring. alert_create_signal = django.dispatch.Signal( ``` ```bash PytestCollectionWarning: cannot collect test class 'TestOnlyBackend' because it has a __init__ constructor (from: apps/api/tests/test_alert_receive_channel_template.py) class TestOnlyBackend(BaseMessagingBackend): ``` ```bash DeprecationWarning: The parameter 'use_aliases' in emoji.emojize() is deprecated and will be removed in version 2.0.0. Use language='alias' instead. To hide this warning, pin/downgrade the package to 'emoji~=1.6.3' return emoji.emojize(self.verbal_name, use_aliases=True) ``` ```bash DateTimeField CustomOnCallShift.start received a naive datetime (2023-06-01 12:53:12) while time zone support is active. warnings.warn("DateTimeField %s received a naive datetime (%s)" ``` ```bash apps/twilioapp/tests/test_phone_calls.py::test_resolve_by_phone /etc/app/apps/twilioapp/tests/test_phone_calls.py:173: DeprecationWarning: The 'text' argument to find()-type methods is deprecated. Use 'string' instead. content = BeautifulSoup(content, features="html.parser").findAll(text=True) ``` ```bash apps/twilioapp/tests/test_phone_calls.py::test_resolve_by_phone apps/twilioapp/tests/test_phone_calls.py::test_wrong_pressed_digit /usr/local/lib/python3.11/site-packages/bs4/builder/__init__.py:545: XMLParsedAsHTMLWarning: It looks like you're parsing an XML document using an HTML parser. If this really is an HTML document (maybe it's XHTML?), you can ignore or filter this warning. If it's XML, you should know that using an XML parser will be more reliable. To parse this document as XML, make sure you have the lxml package installed, and pass the keyword argument `features="xml"` into the BeautifulSoup constructor. ``` ```bash apps/twilioapp/tests/test_phone_calls.py::test_forbidden_requests /usr/local/lib/python3.11/site-packages/social_django/urls.py:15: RemovedInDjango40Warning: django.conf.urls.url() is deprecated in favor of django.urls.re_path(). url(r'^login/(?P<backend>[^/]+){0}$'.format(extra), views.auth, ``` ```bash apps/twilioapp/tests/test_phone_calls.py: 66 warnings /usr/local/lib/python3.11/site-packages/debug_toolbar/utils.py:255: DeprecationWarning: currentThread() is deprecated, use current_thread() instead thread = threading.currentThread() ``` ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
2023-06-06 20:38:00 +02:00
message = emoji.emojize(message, language="alias")
return message
def slack_to_accepted_emoji(self, message):
"""Overridden original method to fix regex that replaces dashes in links"""
message = re.sub(
r":([a-zA-Z0-9<>/:])([^ <>/:]+):", # overridden regex
lambda x: ":{}{}:".format(x.group(1), x.group(2).replace("-", "_")),
message,
)
# https://github.com/Ranks/emojione/issues/114
message = message.replace(":simple_smile:", ":slightly_smiling_face:")
return message
def _sub_hyperlink(self, matchobj):
compound = matchobj.group(0)[1:-1]
if len(compound.split("|")) == 2:
url, title = compound.split("|")
else:
url, title = compound, compound
result = self.hyperlink_mention_format.format(url=url, title=title)
return result
def _sub_annotated_mention(self, matchobj):
"""
Overrided method to use db search instead of self.__USER_DATA and self.__CHANNEL_DATA (see original method)
to search channels and users by their slack_ids
"""
# Matchobj have format <channel_id/channel_name> or <user_id/user_name>
ref_id = matchobj.group(1)[1:] # drop #/@ from the start, we don't care.
annotation = matchobj.group(2)
# check if mention channel
if ref_id.startswith("C"):
mention_format = self.channel_mention_format
# channel could be mentioned only with its slack_id <channel_id>
if not annotation:
# search channel_name by slack_id in cache
annotation = self._sub_annotated_mention_slack_channel(ref_id)
else: # Same for user
mention_format = self.user_mention_format
if not annotation:
annotation = self._sub_annotated_mention_slack_user(ref_id)
return mention_format.format(annotation)
def _sub_annotated_mention_slack_channel(self, ref_id):
channel = None
slack_team_identity = self.__ORGANIZATION.slack_team_identity
if slack_team_identity is not None:
cached_channels = slack_team_identity.get_cached_channels(slack_id=ref_id)
if len(cached_channels) > 0:
channel = cached_channels[0].name
annotation = channel if channel else ref_id
else:
annotation = ref_id
return annotation
def _sub_annotated_mention_slack_user(self, ref_id):
`apps.get_model` -> `import` (#2619) # What this PR does Remove [`apps.get_model`](https://docs.djangoproject.com/en/3.2/ref/applications/#django.apps.apps.get_model) invocations and use inline `import` statements in places where models are imported within functions/methods to avoid circular imports. I believe `import` statements are more appropriate for most use cases as they allow for better static code analysis & formatting, and solve the issue of circular imports without being unnecessarily dynamic as `apps.get_model`. With `import` statements, it's possible to: - Jump to model definitions in most IDEs - Automatically sort inline imports with `isort` - Find import errors faster/easier (most IDEs highlight broken imports) - Have more consistency across regular & inline imports when importing models This PR also adds a flake8 rule to ban imports of `django.apps.apps`, so it's harder to use `apps.get_model` by mistake (it's possible to ignore this rule by using `# noqa: I251`). The rule is not enforced on directories with migration files, because `apps.get_model` is often used to get a historical state of a model, which is useful when writing migrations ([see this SO answer for more details](https://stackoverflow.com/a/37769213)). So `apps.get_model` is considered OK in migrations (even necessary in some cases). ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
2023-07-25 10:43:23 +01:00
from apps.slack.models import SlackUserIdentity
slack_user_identity = SlackUserIdentity.objects.filter(
slack_team_identity=self.__ORGANIZATION.slack_team_identity, slack_id=ref_id
).first()
annotation = ref_id
if slack_user_identity is not None:
if slack_user_identity.profile_display_name:
annotation = slack_user_identity.profile_display_name
elif slack_user_identity.slack_verbal:
annotation = slack_user_identity.slack_verbal
return annotation