Skip to content
Snippets Groups Projects
Commit 19250641 authored by Tore.Brede's avatar Tore.Brede
Browse files

Merge branch 'GREG-5_identity_list' into 'master'

GREG-5: Adding handling of listing and creating identities for persons

See merge request !13
parents fbeb1153 325877e6
No related branches found
No related tags found
1 merge request!13GREG-5: Adding handling of listing and creating identities for persons
Pipeline #89059 passed
from django_filters import rest_framework as filters from django_filters import rest_framework as filters
from greg.models import Person, PersonRole from greg.models import Person, PersonRole, PersonIdentity
class PersonRoleFilter(filters.FilterSet): class PersonRoleFilter(filters.FilterSet):
...@@ -19,3 +19,9 @@ class PersonFilter(filters.FilterSet): ...@@ -19,3 +19,9 @@ class PersonFilter(filters.FilterSet):
class Meta: class Meta:
model = Person model = Person
fields = ["first_name", "last_name", "verified"] fields = ["first_name", "last_name", "verified"]
class PersonIdentityFilter(filters.FilterSet):
class Meta:
model = PersonIdentity
fields = ["type", "verified_by_id"]
from rest_framework import serializers from rest_framework import serializers
from greg.models import Person, PersonRole, Role from greg.models import Person, PersonRole, Role, PersonIdentity
class PersonSerializer(serializers.ModelSerializer): class PersonSerializer(serializers.ModelSerializer):
...@@ -31,3 +31,9 @@ class PersonRoleSerializer(serializers.ModelSerializer): ...@@ -31,3 +31,9 @@ class PersonRoleSerializer(serializers.ModelSerializer):
"updated", "updated",
"role", "role",
] ]
class PersonIdentitySerializer(serializers.ModelSerializer):
class Meta:
model = PersonIdentity
fields = "__all__"
...@@ -13,6 +13,7 @@ from greg.api.views.organizational_unit import OrganizationalUnitViewSet ...@@ -13,6 +13,7 @@ from greg.api.views.organizational_unit import OrganizationalUnitViewSet
from greg.api.views.person import ( from greg.api.views.person import (
PersonRoleViewSet, PersonRoleViewSet,
PersonViewSet, PersonViewSet,
PersonIdentityViewSet,
) )
from greg.api.views.role import RoleViewSet from greg.api.views.role import RoleViewSet
from greg.api.views.health import Health from greg.api.views.health import Health
...@@ -46,4 +47,14 @@ urlpatterns += [ ...@@ -46,4 +47,14 @@ urlpatterns += [
PersonRoleViewSet.as_view({"get": "retrieve"}), PersonRoleViewSet.as_view({"get": "retrieve"}),
name="person_role-detail", name="person_role-detail",
), ),
re_path(
r"^persons/(?P<person_id>[0-9]+)/identities/$",
PersonIdentityViewSet.as_view({"get": "list", "post": "create"}),
name="person_identity-list",
),
re_path(
r"^persons/(?P<person_id>[0-9]+)/identities/(?P<id>[0-9]+)$",
PersonIdentityViewSet.as_view({"delete": "destroy", "patch": "partial_update"}),
name="person_identity-detail",
),
] ]
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django_filters import rest_framework as filters from django_filters import rest_framework as filters
from drf_spectacular.utils import extend_schema, OpenApiParameter from drf_spectacular.utils import extend_schema, OpenApiParameter
from rest_framework import viewsets from rest_framework import viewsets, status
from rest_framework.response import Response
from greg.api.filters import PersonFilter, PersonRoleFilter from greg.api.filters import PersonFilter, PersonRoleFilter, PersonIdentityFilter
from greg.api.pagination import PrimaryKeyCursorPagination from greg.api.pagination import PrimaryKeyCursorPagination
from greg.api.serializers.person import PersonSerializer, PersonRoleSerializer from greg.api.serializers.person import (
from greg.models import Person, PersonRole PersonSerializer,
PersonRoleSerializer,
PersonIdentitySerializer,
)
from greg.models import Person, PersonRole, PersonIdentity
class PersonViewSet(viewsets.ModelViewSet): class PersonViewSet(viewsets.ModelViewSet):
...@@ -62,3 +67,45 @@ class PersonRoleViewSet(viewsets.ModelViewSet): ...@@ -62,3 +67,45 @@ class PersonRoleViewSet(viewsets.ModelViewSet):
raise ValidationError("No person id") raise ValidationError("No person id")
serializer.save(person_id=person_id) serializer.save(person_id=person_id)
class PersonIdentityViewSet(viewsets.ModelViewSet):
"""
Person identity API
"""
queryset = PersonIdentity.objects.all().order_by("id")
serializer_class = PersonIdentitySerializer
pagination_class = PrimaryKeyCursorPagination
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = PersonIdentityFilter
# This is set so that the id parameter in the path of the URL is used for looking up objects
lookup_url_kwarg = "id"
def get_queryset(self):
qs = self.queryset
if not self.kwargs:
return qs.none()
person_id = self.kwargs["person_id"]
qs = qs.filter(person_id=person_id)
return qs
def create(self, request, *args, **kwargs):
# Want to get the person id which is part of the API path and then
# include this with the data used to create the identity for the person
person_id = self.kwargs["person_id"]
if person_id is None:
# Should not happen, the person ID is part of the API path
raise ValidationError("No person id")
input_data = request.data.copy()
input_data["person"] = person_id
serializer = self.get_serializer(data=input_data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(
serializer.data, status=status.HTTP_201_CREATED, headers=headers
)
...@@ -46,6 +46,16 @@ def person_foo_verified(person_foo, sponsor_guy) -> PersonIdentity: ...@@ -46,6 +46,16 @@ def person_foo_verified(person_foo, sponsor_guy) -> PersonIdentity:
) )
@pytest.fixture
def person_foo_not_verified(person_foo) -> PersonIdentity:
return PersonIdentity.objects.create(
person=person_foo,
type=PersonIdentity.IdentityType.DRIVERS_LICENSE,
source="Test",
value="12345",
)
@pytest.fixture @pytest.fixture
def role_visiting_professor() -> Role: def role_visiting_professor() -> Role:
return Role.objects.create( return Role.objects.create(
...@@ -134,3 +144,150 @@ def test_add_role( ...@@ -134,3 +144,150 @@ def test_add_role(
# Check that the role shows up when listing roles for the person now # Check that the role shows up when listing roles for the person now
assert len(roles_for_person) == 1 assert len(roles_for_person) == 1
assert roles_for_person[0]["id"] == response_data["id"] assert roles_for_person[0]["id"] == response_data["id"]
@pytest.mark.django_db
def test_identity_list(
client, person_foo, person_foo_verified, person_foo_not_verified
):
response = client.get(
reverse("person-list"),
data={"first_name": person_foo.first_name, "last_name": person_foo.last_name},
)
person_id = response.json()["results"][0]["id"]
response = client.get(
reverse("person_identity-list", kwargs={"person_id": person_id})
)
data = response.json()["results"]
assert len(data) == 2
@pytest.mark.django_db
def test_identity_add(client, person_foo):
response = client.get(
reverse("person_identity-list", kwargs={"person_id": person_foo.id})
)
results = response.json()["results"]
assert len(results) == 0
data = {
"type": PersonIdentity.IdentityType.FEIDE_ID,
"source": "Test source",
"value": "12345",
}
client.post(
reverse("person_identity-list", kwargs={"person_id": person_foo.id}), data=data
)
response = client.get(
reverse("person_identity-list", kwargs={"person_id": person_foo.id})
)
results = response.json()["results"]
assert len(results) == 1
@pytest.mark.django_db
def test_identity_delete(client, person_foo):
response = client.get(
reverse("person_identity-list", kwargs={"person_id": person_foo.id})
)
results = response.json()["results"]
assert len(results) == 0
data = {
"type": PersonIdentity.IdentityType.FEIDE_ID,
"source": "Test source",
"value": "12345",
}
post_response = client.post(
reverse("person_identity-list", kwargs={"person_id": person_foo.id}), data=data
)
identity_id = post_response.json()["id"]
# Create two identities for the user
data = {
"type": PersonIdentity.IdentityType.PASSPORT,
"source": "Test",
"value": "1234413241235",
}
post_response2 = client.post(
reverse("person_identity-list", kwargs={"person_id": person_foo.id}), data=data
)
identity_id2 = post_response2.json()["id"]
response = client.get(
reverse("person_identity-list", kwargs={"person_id": person_foo.id})
)
results = response.json()["results"]
assert len(results) == 2
# Delete the first identity created
client.delete(
reverse(
"person_identity-detail",
kwargs={"person_id": person_foo.id, "id": identity_id},
)
)
# Check that the other identity is still there
response = client.get(
reverse("person_identity-list", kwargs={"person_id": person_foo.id})
)
results = response.json()["results"]
assert len(results) == 1
assert results[0]["id"] == identity_id2
@pytest.mark.django_db
def test_identity_update(client, person_foo):
response = client.get(
reverse("person_identity-list", kwargs={"person_id": person_foo.id})
)
results = response.json()["results"]
assert len(results) == 0
data = {
"type": PersonIdentity.IdentityType.FEIDE_ID,
"source": "Test source",
"value": "12345",
}
client.post(
reverse("person_identity-list", kwargs={"person_id": person_foo.id}), data=data
)
response = client.get(
reverse("person_identity-list", kwargs={"person_id": person_foo.id})
)
results = response.json()["results"]
assert len(results) == 1
identity_id = results[0]["id"]
assert results[0]["type"] == data["type"]
assert results[0]["source"] == data["source"]
assert results[0]["value"] == data["value"]
data_updated = {
"type": PersonIdentity.IdentityType.PASSPORT,
"source": "Test",
"value": "10000",
}
patch_response = client.patch(
reverse(
"person_identity-detail",
kwargs={"person_id": person_foo.id, "id": identity_id},
),
data=data_updated,
)
assert patch_response.status_code == status.HTTP_200_OK
response = client.get(
reverse("person_identity-list", kwargs={"person_id": person_foo.id})
)
results = response.json()["results"]
assert len(results) == 1
assert results[0]["type"] == data_updated["type"]
assert results[0]["source"] == data_updated["source"]
assert results[0]["value"] == data_updated["value"]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment