2022-06-03 08:09:47 -06:00
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
import emoji
|
2023-06-27 12:23:08 +02:00
|
|
|
from slackviewer.formatter import SlackFormatter as SlackFormatterBase
|
2022-06-03 08:09:47 -06:00
|
|
|
|
|
|
|
|
|
2023-06-27 12:23:08 +02:00
|
|
|
class SlackFormatter(SlackFormatterBase):
|
2022-06-03 08:09:47 -06:00
|
|
|
_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)
|
2022-06-03 08:09:47 -06:00
|
|
|
|
|
|
|
|
# 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")
|
2022-06-03 08:09:47 -06:00
|
|
|
|
|
|
|
|
return message
|
|
|
|
|
|
2023-11-24 16:39:37 +01:00
|
|
|
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
|
|
|
|
|
|
2022-06-03 08:09:47 -06:00
|
|
|
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):
|
2023-07-25 10:43:23 +01:00
|
|
|
from apps.slack.models import SlackUserIdentity
|
2022-06-03 08:09:47 -06:00
|
|
|
|
|
|
|
|
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
|