Skip to content

Commit ec96912

Browse files
authored
Merge pull request #458 from NHSDigital/10973-add-roles
Add roles to UserAssignment
2 parents a999964 + 4f9d862 commit ec96912

File tree

3 files changed

+108
-31
lines changed

3 files changed

+108
-31
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Generated by Django 5.2.6 on 2025-09-29 14:01
2+
3+
import django.contrib.postgres.fields
4+
import django.core.validators
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('clinics', '0017_alter_userassignment_options'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='userassignment',
17+
name='roles',
18+
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(choices=[('Clinical', 'Clinical'), ('Administrative', 'Administrative')], max_length=32), default=list, help_text='Roles granted to the user for this provider.', size=None, validators=[django.core.validators.MinLengthValidator(1)]),
19+
),
20+
]

manage_breast_screening/clinics/models.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
from enum import StrEnum
44

55
from django.conf import settings
6+
from django.contrib.postgres.fields import ArrayField
7+
from django.core.validators import MinLengthValidator
68
from django.db import models
79

10+
from ..auth.models import Role
811
from ..core.models import BaseModel
912

1013

@@ -189,6 +192,24 @@ class UserAssignment(BaseModel):
189192
provider = models.ForeignKey(
190193
Provider, on_delete=models.PROTECT, related_name="assignments"
191194
)
195+
roles = ArrayField(
196+
base_field=models.CharField(
197+
max_length=32,
198+
choices=[
199+
(Role.CLINICAL.value, Role.CLINICAL.value),
200+
(Role.ADMINISTRATIVE.value, Role.ADMINISTRATIVE.value),
201+
],
202+
),
203+
default=list,
204+
validators=[MinLengthValidator(1)],
205+
help_text="Roles granted to the user for this provider.",
206+
)
207+
208+
def save(self, *args, **kwargs):
209+
if self.roles:
210+
# Remove duplicates and sort
211+
self.roles = sorted(list(set(self.roles)))
212+
super().save(*args, **kwargs)
192213

193214
class Meta:
194215
unique_together = ["user", "provider"]

manage_breast_screening/clinics/tests/test_models.py

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import time_machine
66
from pytest_django.asserts import assertQuerySetEqual
77

8+
from manage_breast_screening.auth.models import Role
89
from manage_breast_screening.clinics import models
910

1011
from .factories import (
@@ -38,37 +39,72 @@ def test_status_filtering():
3839
assertQuerySetEqual(models.Clinic.objects.completed(), {past}, ordered=False)
3940

4041

41-
@pytest.mark.django_db
42-
def test_user_assignment_creation():
43-
assignment = UserAssignmentFactory()
44-
assert assignment.user is not None
45-
assert assignment.provider is not None
46-
assert assignment.pk is not None
47-
48-
49-
@pytest.mark.django_db
50-
def test_user_assignment_str():
51-
user = UserFactory(first_name="John", last_name="Doe")
52-
provider = ProviderFactory(name="Test Provider")
53-
assignment = UserAssignmentFactory(user=user, provider=provider)
54-
assert str(assignment) == "John Doe → Test Provider"
55-
42+
class TestUserAssignment:
43+
def test_str(self):
44+
user = UserFactory.build(first_name="John", last_name="Doe")
45+
provider = ProviderFactory.build(name="Test Provider")
46+
assignment = UserAssignmentFactory.build(user=user, provider=provider)
47+
assert str(assignment) == "John Doe → Test Provider"
5648

57-
@pytest.mark.django_db
58-
def test_user_assignment_unique_constraint():
59-
user = UserFactory()
60-
provider = ProviderFactory()
61-
UserAssignmentFactory(user=user, provider=provider)
62-
63-
with pytest.raises(Exception):
49+
@pytest.mark.django_db
50+
def test_unique_constraint(self):
51+
user = UserFactory()
52+
provider = ProviderFactory()
6453
UserAssignmentFactory(user=user, provider=provider)
6554

66-
67-
@pytest.mark.django_db
68-
def test_user_assignment_related_names():
69-
user = UserFactory()
70-
provider = ProviderFactory()
71-
assignment = UserAssignmentFactory(user=user, provider=provider)
72-
73-
assert assignment in user.assignments.all()
74-
assert assignment in provider.assignments.all()
55+
with pytest.raises(Exception):
56+
UserAssignmentFactory(user=user, provider=provider)
57+
58+
@pytest.mark.django_db
59+
def test_related_names(self):
60+
user = UserFactory()
61+
provider = ProviderFactory()
62+
assignment = UserAssignmentFactory(user=user, provider=provider)
63+
64+
assert assignment in user.assignments.all()
65+
assert assignment in provider.assignments.all()
66+
67+
@pytest.mark.django_db
68+
def test_roles_ordering(self):
69+
"""Test that roles are sorted alphabetically for consistent ordering."""
70+
user = UserFactory()
71+
provider = ProviderFactory()
72+
73+
# Create assignment with roles in reverse alphabetical order
74+
assignment = UserAssignmentFactory(
75+
user=user,
76+
provider=provider,
77+
roles=[Role.CLINICAL.value, Role.ADMINISTRATIVE.value],
78+
)
79+
80+
assert assignment.roles == [Role.ADMINISTRATIVE.value, Role.CLINICAL.value]
81+
82+
@pytest.mark.django_db
83+
def test_roles_single_role(self):
84+
"""Test that single role works correctly."""
85+
user = UserFactory()
86+
provider = ProviderFactory()
87+
88+
assignment = UserAssignmentFactory(
89+
user=user, provider=provider, roles=[Role.CLINICAL.value]
90+
)
91+
92+
assert assignment.roles == [Role.CLINICAL.value]
93+
94+
@pytest.mark.django_db
95+
def test_roles_duplicate_values(self):
96+
"""Test that duplicate roles are deduplicated and sorted on save."""
97+
user = UserFactory()
98+
provider = ProviderFactory()
99+
100+
assignment = UserAssignmentFactory(
101+
user=user,
102+
provider=provider,
103+
roles=[Role.CLINICAL.value, Role.CLINICAL.value, Role.ADMINISTRATIVE.value],
104+
)
105+
106+
# Should be sorted and deduplicated
107+
assert assignment.roles == [
108+
Role.ADMINISTRATIVE.value,
109+
Role.CLINICAL.value,
110+
]

0 commit comments

Comments
 (0)