Skip to content

Commit 8ddbde7

Browse files
committed
use LASTNAME, firstname (Role) format in header
This format is a convention used across clinical applications. It used to be mandated as part of the common interface standard. Although it is not mandated any more, we don't want to diverge from the convention without a good reason. Constructing `role_and_text` in the template itself is a bit awkward. We can't put it in jinja_env.py because we need access to `request.user`. We could create a context processor for this, but the django docs discourage using context processors with jinja: https://docs.djangoproject.com/en/5.2/topics/templates/#django.template.backends.jinja2.Jinja2
1 parent 5d47d0c commit 8ddbde7

File tree

4 files changed

+123
-59
lines changed

4 files changed

+123
-59
lines changed

manage_breast_screening/config/jinja2_env.py

Lines changed: 16 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,14 @@
22
from django.templatetags.static import static
33
from django.urls import reverse
44
from jinja2 import ChoiceLoader, Environment, PackageLoader
5-
from markupsafe import Markup, escape
65

7-
8-
def no_wrap(value):
9-
"""
10-
Wrap a string in a span with class app-no-wrap
11-
12-
>>> no_wrap('a really long string')
13-
Markup('<span class="nhsuk-u-nowrap">a really long string</span>')
14-
"""
15-
return Markup(
16-
f'<span class="nhsuk-u-nowrap">{escape(value)}</span>' if value else ""
17-
)
18-
19-
20-
def nl2br(value):
21-
"""
22-
Convert newline characters to html line breaks
23-
24-
>>> nl2br('foo\\nbar\\nbaz')
25-
Markup('foo<br>bar<br>baz')
26-
27-
>>> nl2br('<script>\\n</script>')
28-
Markup('&lt;script&gt;<br>&lt;/script&gt;')
29-
"""
30-
lines = value.splitlines()
31-
return Markup("<br>".join([escape(line) for line in lines]))
32-
33-
34-
def as_hint(value):
35-
"""
36-
Wrap a string in a span with class nhsuk-u-secondary-text-color
37-
38-
>>> as_hint('Not provided')
39-
Markup('<span class=nhsuk-u-secondary-text-color">Not provided</span>')
40-
"""
41-
return Markup(
42-
f'<span class=nhsuk-u-secondary-text-color">{value}</span>' if value else ""
43-
)
44-
45-
46-
def raise_helper(msg):
47-
raise Exception(msg)
6+
from manage_breast_screening.core.template_helpers import (
7+
as_hint,
8+
header_account_items,
9+
nl2br,
10+
no_wrap,
11+
raise_helper,
12+
)
4813

4914

5015
def autoescape(template_name):
@@ -82,10 +47,17 @@ def environment(**options):
8247
)
8348

8449
env.globals.update(
85-
{"static": static, "url": reverse, "STATIC_URL": settings.STATIC_URL}
50+
{
51+
"STATIC_URL": settings.STATIC_URL,
52+
"header_account_items": header_account_items,
53+
"raise": raise_helper,
54+
"static": static,
55+
"url": reverse,
56+
}
8657
)
58+
8759
env.filters["no_wrap"] = no_wrap
8860
env.filters["as_hint"] = as_hint
8961
env.filters["nl2br"] = nl2br
90-
env.globals["raise"] = raise_helper
62+
9163
return env

manage_breast_screening/core/jinja2/layout-app.jinja

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,15 @@
66
<link rel="stylesheet" href="{{ static('css/main.css' )}}">
77
{% endblock %}
88

9-
{% block pageTitle %}{% if form and form.errors %}Error: {% endif %}{% if page_title %}{{page_title}} – {% endif %}Manage breast screening – NHS{% endblock %}
9+
{% block pageTitle %}{% if form and form.errors %}Error: {% endif %}{% if page_title %}{{ page_title }} – {% endif %}Manage breast screening – NHS{% endblock %}
1010

1111
{% block header %}
12-
{% set account_items = [] %}
13-
{% if request.user.is_authenticated %}
14-
{% do account_items.append({
15-
"text": request.user.first_name ~ ' ' ~ request.user.last_name,
16-
"icon": true
17-
}) %}
18-
{% endif %}
19-
20-
{% do account_items.append({
21-
"href": url('auth:logout') if request and request.user.is_authenticated else url('auth:login'),
22-
"text": "Log out" if request and request.user.is_authenticated else "Log in",
23-
}) %}
24-
2512
{{ header({
2613
"service": {
2714
"name": "Manage breast screening"
2815
},
2916
"account": {
30-
"items": account_items
17+
"items": header_account_items(request.user)
3118
},
3219
"navigation": {
3320
"items": [
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
from django.urls import reverse
2+
from markupsafe import Markup, escape
3+
4+
5+
def no_wrap(value):
6+
"""
7+
Wrap a string in a span with class app-no-wrap
8+
9+
>>> no_wrap('a really long string')
10+
Markup('<span class="nhsuk-u-nowrap">a really long string</span>')
11+
"""
12+
return Markup(
13+
f'<span class="nhsuk-u-nowrap">{escape(value)}</span>' if value else ""
14+
)
15+
16+
17+
def nl2br(value):
18+
"""
19+
Convert newline characters to html line breaks
20+
21+
>>> nl2br('foo\\nbar\\nbaz')
22+
Markup('foo<br>bar<br>baz')
23+
24+
>>> nl2br('<script>\\n</script>')
25+
Markup('&lt;script&gt;<br>&lt;/script&gt;')
26+
"""
27+
lines = value.splitlines()
28+
return Markup("<br>".join([escape(line) for line in lines]))
29+
30+
31+
def as_hint(value):
32+
"""
33+
Wrap a string in a span with class nhsuk-u-secondary-text-color
34+
35+
>>> as_hint('Not provided')
36+
Markup('<span class=nhsuk-u-secondary-text-color">Not provided</span>')
37+
"""
38+
return Markup(
39+
f'<span class=nhsuk-u-secondary-text-color">{value}</span>' if value else ""
40+
)
41+
42+
43+
def raise_helper(msg):
44+
raise Exception(msg)
45+
46+
47+
def _user_name_and_role_item(user):
48+
if user.is_authenticated:
49+
name_and_role_text = f"{user.last_name.upper()}, {user.first_name}"
50+
roles = list(user.groups.all())
51+
if roles:
52+
name_and_role_text += f" ({', '.join(role.name for role in roles)})"
53+
54+
return {"text": name_and_role_text, "icon": True}
55+
56+
57+
def header_account_items(user):
58+
items = []
59+
60+
user_name_and_role = _user_name_and_role_item(user)
61+
if user_name_and_role:
62+
items.append(user_name_and_role)
63+
64+
items.append(
65+
{
66+
"href": (
67+
reverse("auth:logout")
68+
if user.is_authenticated
69+
else reverse("auth:login")
70+
),
71+
"text": "Log out" if user.is_authenticated else "Log in",
72+
}
73+
)
74+
75+
return items
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import pytest
2+
from django.contrib.auth.models import AnonymousUser
3+
4+
from manage_breast_screening.auth.tests.factories import UserFactory
5+
from manage_breast_screening.core.template_helpers import header_account_items
6+
7+
8+
@pytest.mark.django_db
9+
class TestHeaderAccountItems:
10+
def test_user_with_no_role(self):
11+
user = UserFactory.create(first_name="Firstname", last_name="Lastname")
12+
assert header_account_items(user) == [
13+
{"text": "LASTNAME, Firstname", "icon": True},
14+
{"href": "/auth/log-out/", "text": "Log out"},
15+
]
16+
17+
def test_user_with_role(self):
18+
user = UserFactory.create(
19+
first_name="Firstname", last_name="Lastname", groups__clinical=True
20+
)
21+
assert header_account_items(user) == [
22+
{"text": "LASTNAME, Firstname (Clinical)", "icon": True},
23+
{"href": "/auth/log-out/", "text": "Log out"},
24+
]
25+
26+
def test_anonymous_user(self):
27+
user = AnonymousUser()
28+
assert header_account_items(user) == [
29+
{"href": "/auth/log-in/", "text": "Log in"},
30+
]

0 commit comments

Comments
 (0)