Coverage for src / mesh / templatetags / mesh_tags.py: 73%
108 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-10-22 07:20 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-10-22 07:20 +0000
1import datetime
2import re
3from logging import getLogger
5from dateutil.relativedelta import relativedelta
6from django import template
7from django.http import HttpRequest
8from django.template.defaultfilters import stringfilter
9from django.template.loader import render_to_string
10from django.utils.html import escape, mark_safe
11from opentelemetry.trace import get_tracer
13from mesh.models.file_helpers import file_name as original_file_name
14from mesh.models.orm.submission_models import SUBMISSION_STATE_CHOICES
15from mesh.models.user.user_interfaces import ImpersonateData
16from mesh.views.components.icon import Icon
17from mesh.views.forms.role_forms import RoleSwitchForm
19register = template.Library()
21logger = getLogger(__name__)
22tracer = get_tracer(__name__)
25@register.filter
26def render_attrs(attrs):
27 """Render a Dict[str, List[str]] as HTML attributes."""
28 try:
29 parts = []
30 for attr, values in attrs.items():
31 value = " ".join(str(v) for v in values)
32 parts.append(f'{attr}="{value}"')
33 return mark_safe(" ".join(parts))
34 except TypeError:
35 return ""
36 except AttributeError:
37 return ""
40@register.filter
41@stringfilter
42def file_name(file_path: str) -> str:
43 """
44 Returns the base name of a file from its path.
45 """
46 return original_file_name(file_path)
49@register.filter
50@stringfilter
51def role_switch_form(role_code: str) -> RoleSwitchForm:
52 """
53 Returns a RoleSwitchForm whose POST switches the user current role to
54 the provided role code.
55 """
56 return RoleSwitchForm(initial={"role_code": role_code})
59@register.simple_tag(takes_context=True)
60def check_rights(context, function_name: str, *args, **kwargs) -> bool:
61 """
62 Wrapper around `RoleHandler.check_rights` method for use in template.
63 """
64 role = context["request"].current_role
65 fct = getattr(role, function_name, None)
66 if not fct:
67 logger.error(f"function {function_name} not found for role {role}")
68 return False
69 return fct(*args, **kwargs)
72@register.filter
73def get_impersonate_data(request: HttpRequest) -> ImpersonateData | None:
74 return ImpersonateData.from_session(request.session)
77@register.filter
78@stringfilter
79def filter_email(value):
80 new_value = re.sub(r"\(.*\@.*\)", "", value)
81 return new_value
84@register.filter
85def get_delay(date):
86 today = datetime.date.today()
88 # delta = date - today
89 delta = relativedelta(date, today)
91 days = delta.days
92 weeks = delta.weeks
93 months = delta.months
94 years = delta.years
95 abs_days = abs(days)
96 abs_weeks = abs(weeks)
97 abs_months = abs(months)
98 abs_years = abs(years)
100 badge_class = "success"
102 if date == today:
103 value = "today"
104 badge_class = "warning"
105 elif days == 1 and months == 0:
106 value = "tomorrow"
107 badge_class = "warning"
108 elif days == -1 and months == 0:
109 value = "yesterday"
110 badge_class = "error"
111 else:
112 if abs_years == 1:
113 value = "1 year"
114 elif abs_years > 1:
115 value = f"{abs_years} years"
116 elif abs_months == 1:
117 value = "1 month"
118 elif abs_months > 1:
119 value = f"{abs_months} months"
120 elif days % 7 == 0:
121 if abs_weeks == 1:
122 value = "1 week"
123 else:
124 value = f"{abs_weeks} weeks"
125 else:
126 value = f"{abs_days} days"
127 if abs_days < 7:
128 badge_class = "warning"
130 if days > 0 or months > 0 or years > 1:
131 value = "in " + value
132 else:
133 value = value + " ago"
134 badge_class = "error"
136 value = f'<span class="badge rounded-pill badge-{badge_class}">{value}</span>'
137 return value
140@register.filter
141@stringfilter
142def get_state_display(value):
143 results = [s[1] for s in SUBMISSION_STATE_CHOICES if s[0] == value]
144 if len(results) > 0:
145 value = results[0]
146 return value
149@register.simple_tag
150def render_icon_escaped(icon: Icon):
151 html = render_to_string(
152 "mesh/components/icon.html",
153 {
154 "icon_class": icon.icon_class,
155 "icon_attrs": icon.icon_attrs,
156 },
157 )
158 return escape(html)