diff --git a/src/sentry/notifications/notifications/activity/base.py b/src/sentry/notifications/notifications/activity/base.py
index 19996f673ba9c1..cb4e6eff1440d2 100644
--- a/src/sentry/notifications/notifications/activity/base.py
+++ b/src/sentry/notifications/notifications/activity/base.py
@@ -6,7 +6,7 @@
from urllib.parse import urlparse, urlunparse
from django.utils.html import format_html
-from django.utils.safestring import SafeString, mark_safe
+from django.utils.safestring import SafeString
from sentry.db.models import Model
from sentry.notifications.helpers import get_reason_context
@@ -186,7 +186,7 @@ def description_as_html(self, description: str, params: Mapping[str, Any]) -> Sa
fmt = '{} {}'
- author = format_html(fmt, mark_safe(avatar_as_html(self.user)), name)
+ author = format_html(fmt, avatar_as_html(self.user), name)
issue_name = self.group.qualified_short_id or "an issue"
an_issue = format_html('{}', self.get_group_link(), issue_name)
diff --git a/src/sentry/notifications/utils/avatar.py b/src/sentry/notifications/utils/avatar.py
index a74131b83ff8e5..ea62e42adaacdb 100644
--- a/src/sentry/notifications/utils/avatar.py
+++ b/src/sentry/notifications/utils/avatar.py
@@ -1,7 +1,8 @@
from __future__ import annotations
from django.urls import reverse
-from django.utils.html import escape
+from django.utils.html import format_html
+from django.utils.safestring import SafeString
from sentry.models.avatars.user_avatar import UserAvatar
from sentry.models.user import User
@@ -37,14 +38,14 @@ def get_sentry_avatar_url() -> str:
return str(absolute_uri(get_asset_url("sentry", url)))
-def avatar_as_html(user: User | RpcUser) -> str:
+def avatar_as_html(user: User | RpcUser) -> SafeString:
if not user:
- return '
'.format(
- escape(get_sentry_avatar_url())
+ return format_html(
+ '
', get_sentry_avatar_url()
)
avatar_type = user.get_avatar_type()
if avatar_type == "upload":
- return f'
'
+ return format_html('
', get_user_avatar_url(user))
elif avatar_type == "letter_avatar":
return get_email_avatar(user.get_display_name(), user.get_label(), 20, False)
else:
diff --git a/src/sentry/templatetags/sentry_avatars.py b/src/sentry/templatetags/sentry_avatars.py
index 8b77932f03b67f..718715613f0ed6 100644
--- a/src/sentry/templatetags/sentry_avatars.py
+++ b/src/sentry/templatetags/sentry_avatars.py
@@ -2,7 +2,6 @@
from django import template
from django.urls import reverse
-from django.utils.safestring import mark_safe
from sentry.models.avatars.user_avatar import UserAvatar
from sentry.models.user import User
@@ -23,7 +22,7 @@ def gravatar_url(context, email, size, default="mm"):
@register.simple_tag(takes_context=True)
def letter_avatar_svg(context, display_name, identifier, size=None):
- return mark_safe(get_letter_avatar(display_name, identifier, size=size))
+ return get_letter_avatar(display_name, identifier, size=size)
@register.simple_tag(takes_context=True)
@@ -42,7 +41,7 @@ def profile_photo_url(context, user_id, size=None):
# than 1-2 avatars. It will make a request for every user!
@register.simple_tag(takes_context=True)
def email_avatar(context, display_name, identifier, size=None, try_gravatar=True):
- return mark_safe(get_email_avatar(display_name, identifier, size, try_gravatar))
+ return get_email_avatar(display_name, identifier, size, try_gravatar)
@register.inclusion_tag("sentry/partial/avatar.html")
diff --git a/src/sentry/templatetags/sentry_platforms.py b/src/sentry/templatetags/sentry_platforms.py
index 1d2524531a1bf1..0cb90a2489a2af 100644
--- a/src/sentry/templatetags/sentry_platforms.py
+++ b/src/sentry/templatetags/sentry_platforms.py
@@ -1,5 +1,4 @@
from django import template
-from django.utils.safestring import mark_safe
from sentry.utils.avatar import get_letter_avatar, get_platform_avatar
@@ -8,18 +7,16 @@
@register.simple_tag(takes_context=True)
def letter_platform_svg(context, display_name, identifier, size=None, rounded=False):
- return mark_safe(
- get_letter_avatar(
- display_name,
- identifier,
- size,
- use_svg=False,
- initials=display_name[0:2] if display_name else None,
- rounded=rounded,
- )
+ return get_letter_avatar(
+ display_name,
+ identifier,
+ size,
+ use_svg=False,
+ initials=display_name[0:2] if display_name else None,
+ rounded=rounded,
)
@register.simple_tag(takes_context=True)
def platform_avatar(context, display_name, size=36):
- return mark_safe(get_platform_avatar(display_name, size))
+ return get_platform_avatar(display_name, size)
diff --git a/src/sentry/utils/avatar.py b/src/sentry/utils/avatar.py
index e20a964a6855fe..3ee9a0ce53c0cc 100644
--- a/src/sentry/utils/avatar.py
+++ b/src/sentry/utils/avatar.py
@@ -11,7 +11,8 @@
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
from django.utils.encoding import force_str
-from django.utils.html import escape
+from django.utils.html import escape, format_html
+from django.utils.safestring import SafeString
from PIL import Image
from sentry.http import safe_urlopen
@@ -74,7 +75,7 @@ def get_letter_avatar(
use_svg: Optional[bool] = True,
initials: Optional[str] = None,
rounded: Optional[bool] = False,
-) -> str:
+) -> SafeString:
display_name = (display_name or "").strip() or "?"
names = display_name.split(" ")
initials = initials or "{}{}".format(names[0][0], names[-1][0] if len(names) > 1 else "")
@@ -82,24 +83,26 @@ def get_letter_avatar(
color = get_letter_avatar_color(identifier)
if use_svg:
size_attrs = f'height="{size}" width="{size}"' if size else ""
- return (
+ return format_html(
'"
- ).format(color=color, initials=initials, size_attrs=size_attrs)
+ "",
+ color=color,
+ initials=initials,
+ size_attrs=size_attrs,
+ )
else:
size_attrs = f"height:{size}px;width:{size}px;" if size else ""
font_size = "font-size:%spx;" % (size / 2) if size else ""
line_height = "line-height:%spx;" % size if size else ""
span_class = " rounded" if rounded else ""
- return (
+ return format_html(
''
- "{initials}"
- ).format(
+ "{initials}",
color=color,
initials=initials,
size_attrs=size_attrs,
@@ -114,7 +117,7 @@ def get_email_avatar(
identifier: str,
size: Optional[int] = None,
try_gravatar: Optional[bool] = True,
-) -> str:
+) -> SafeString:
if try_gravatar:
try:
validate_email(identifier)
@@ -129,16 +132,20 @@ def get_email_avatar(
if resp.status_code == 200:
# default to mm if including in emails
gravatar_url = get_gravatar_url(identifier, size=size)
- return f'
'
+ return format_html('
', gravatar_url)
return get_letter_avatar(display_name, identifier, size, use_svg=False)
def get_platform_avatar(
display_name: Optional[str],
size: Optional[int] = None,
-) -> str:
+) -> SafeString:
# TODO: @taylangocmen add platformicons from package when available
- return f'
'
+ return format_html(
+ '
',
+ display_name=display_name,
+ size=size,
+ )
def is_black_alpha_only(data: IO[bytes]) -> bool: