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( '' '' '' "{initials}" "" - "" - ).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: