Skip to content
Snippets Groups Projects
Commit 54675fe3 authored by Jonas Braathen's avatar Jonas Braathen
Browse files

Add an invitation status field to the guest serializer for use in the UI.

Move serializers only used by gregui.
parent 27d594b8
No related branches found
No related tags found
1 merge request!299Show invitation status
......@@ -16,9 +16,3 @@ class IdentitySerializer(serializers.ModelSerializer):
if self.is_duplicate(attrs["type"], attrs["value"]):
raise ValidationError("Identity already exists")
return attrs
class SpecialIdentitySerializer(serializers.ModelSerializer):
class Meta:
model = Identity
fields = ["id", "value", "type", "verified_at"]
from rest_framework import serializers
from rest_framework.fields import BooleanField, CharField, SerializerMethodField
from greg.api.serializers.consent import ConsentSerializerBrief
from greg.api.serializers.identity import IdentitySerializer, SpecialIdentitySerializer
from greg.api.serializers.role import RoleSerializer, SpecialRoleSerializer
from greg.api.serializers.identity import IdentitySerializer
from greg.api.serializers.role import RoleSerializer
from greg.models import Person
......@@ -25,54 +24,3 @@ class PersonSerializer(serializers.ModelSerializer):
"roles",
"consents",
]
class SpecialPersonSerializer(serializers.ModelSerializer):
"""
Serializer for the person endpoint
Can be used to change or add an email to the person
"""
pid = CharField(source="id", read_only=True)
first = CharField(source="first_name", read_only=True)
last = CharField(source="last_name", read_only=True)
email = SerializerMethodField(source="private_email")
mobile = SerializerMethodField(source="private_mobile", read_only=True)
fnr = SpecialIdentitySerializer(read_only=True)
passport = SpecialIdentitySerializer(read_only=True)
feide_id = SerializerMethodField(source="feide_id", read_only=True)
active = SerializerMethodField(source="active", read_only=True)
registered = BooleanField(source="is_registered", read_only=True)
verified = BooleanField(source="is_verified", read_only=True)
roles = SpecialRoleSerializer(many=True, read_only=True)
def get_email(self, obj):
return obj.private_email and obj.private_email.value
def get_mobile(self, obj):
return obj.private_mobile and obj.private_mobile.value
def get_active(self, obj):
return obj.is_registered and obj.is_verified
def get_feide_id(self, obj):
return obj.feide_id and obj.feide_id.value
class Meta:
model = Person
fields = [
"pid",
"first",
"last",
"mobile",
"fnr",
"email",
"passport",
"feide_id",
"active",
"registered",
"verified",
"roles",
]
from rest_framework import serializers
from rest_framework.fields import IntegerField, SerializerMethodField
from rest_framework.fields import IntegerField
from greg.api.serializers.organizational_unit import OrganizationalUnitSerializer
from greg.models import Role, RoleType
......@@ -42,44 +42,3 @@ class RoleWriteSerializer(RoleSerializer):
"""
orgunit = IntegerField(source="orgunit_id") # type: ignore
class SpecialRoleSerializer(serializers.ModelSerializer):
name_nb = SerializerMethodField(source="type")
name_en = SerializerMethodField(source="type")
ou_nb = SerializerMethodField(source="orgunit")
ou_en = SerializerMethodField(source="orgunit")
max_days = SerializerMethodField(source="type")
def get_name_nb(self, obj):
return obj.type.name_nb
def get_name_en(self, obj):
return obj.type.name_en
def get_ou_nb(self, obj):
return obj.orgunit.name_nb
def get_ou_en(self, obj):
return obj.orgunit.name_en
def get_max_days(self, obj):
return obj.type.max_days
class Meta:
model = Role
fields = [
"id",
"name_nb",
"name_en",
"ou_nb",
"ou_en",
"start_date",
"end_date",
"max_days",
"contact_person_unit",
"comments",
]
read_only_fields = [
"contact_person_unit",
]
import datetime
from django.conf import settings
from django.utils.timezone import now
from django.utils import timezone
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.fields import BooleanField, CharField, SerializerMethodField
<<<<<<< HEAD
from greg.models import Consent, ConsentChoice, ConsentType, Identity, Person
from greg.utils import is_identity_duplicate
from gregui.api.serializers.IdentityDuplicateError import IdentityDuplicateError
=======
from greg.models import (
Consent,
ConsentChoice,
ConsentType,
Identity,
Person,
InvitationLink,
)
from gregui.api.serializers.identity import PartialIdentitySerializer
from gregui.api.serializers.role import ExtendedRoleSerializer
>>>>>>> 5be5116 (Add an invitation status field to the guest serializer for use in the UI.)
from gregui.validation import (
validate_phone_number,
validate_norwegian_national_id_number,
)
def create_identity_or_update(
identity_type: Identity.IdentityType, value: str, person: Person
):
existing_identity = person.identities.filter(type=identity_type).first()
if not existing_identity:
Identity.objects.create(
person=person,
type=identity_type,
source=settings.DEFAULT_IDENTITY_SOURCE,
value=value,
)
else:
existing_identity.value = value
existing_identity.save()
# pylint: disable=W0223
class GuestConsentChoiceSerializer(serializers.Serializer):
type = serializers.CharField(required=True)
......@@ -107,7 +138,7 @@ class GuestRegisterSerializer(serializers.ModelSerializer):
type=consent_type,
person=person,
choice=choice,
defaults={"consent_given_at": now()},
defaults={"consent_given_at": timezone.now()},
)
if not created and consent_instance.choice != choice:
consent_instance.choice = choice
......@@ -194,17 +225,64 @@ class GuestRegisterSerializer(serializers.ModelSerializer):
read_only_fields = ("id",)
def create_identity_or_update(
identity_type: Identity.IdentityType, value: str, person: Person
):
existing_identity = person.identities.filter(type=identity_type).first()
if not existing_identity:
Identity.objects.create(
person=person,
type=identity_type,
source=settings.DEFAULT_IDENTITY_SOURCE,
value=value,
class GuestSerializer(serializers.ModelSerializer):
"""
Serializer used for presenting guests to sponsors.
"""
pid = CharField(source="id", read_only=True)
first = CharField(source="first_name", read_only=True)
last = CharField(source="last_name", read_only=True)
email = SerializerMethodField(source="private_email")
mobile = SerializerMethodField(source="private_mobile", read_only=True)
fnr = PartialIdentitySerializer(read_only=True)
passport = PartialIdentitySerializer(read_only=True)
feide_id = SerializerMethodField(source="feide_id", read_only=True)
active = SerializerMethodField(source="active", read_only=True)
registered = BooleanField(source="is_registered", read_only=True)
verified = BooleanField(source="is_verified", read_only=True)
invitation_status = SerializerMethodField(
source="get_invitation_status", read_only=True
)
roles = ExtendedRoleSerializer(many=True, read_only=True)
def get_email(self, obj):
return obj.private_email and obj.private_email.value
def get_mobile(self, obj):
return obj.private_mobile and obj.private_mobile.value
def get_active(self, obj):
return obj.is_registered and obj.is_verified
def get_feide_id(self, obj):
return obj.feide_id and obj.feide_id.value
def get_invitation_status(self, obj):
invitation_links = InvitationLink.objects.filter(
invitation__role__person__id=obj.id
)
else:
existing_identity.value = value
existing_identity.save()
non_expired_links = invitation_links.filter(expire__gt=timezone.now())
if non_expired_links.count():
return "active"
if invitation_links.count():
return "expired"
return "none"
class Meta:
model = Person
fields = [
"pid",
"first",
"last",
"mobile",
"fnr",
"email",
"passport",
"feide_id",
"active",
"registered",
"verified",
"invitation_status",
"roles",
]
......@@ -61,3 +61,9 @@ class IdentitySerializer(serializers.ModelSerializer):
attrs["verified_by"] = self._get_sponsor()
attrs["verified_at"] = timezone.now()
return attrs
class PartialIdentitySerializer(serializers.ModelSerializer):
class Meta:
model = Identity
fields = ["id", "value", "type", "verified_at"]
import datetime
from rest_framework import serializers
from rest_framework.fields import SerializerMethodField
from rest_framework.exceptions import ValidationError
from rest_framework.validators import UniqueTogetherValidator
......@@ -89,3 +90,49 @@ class InviteRoleSerializerUi(RoleSerializerUi):
"comments",
"available_in_search",
]
class ExtendedRoleSerializer(serializers.ModelSerializer):
"""
A role serializer with additional human readable names for the
role type and associated organizational unit.
"""
name_nb = SerializerMethodField(source="type")
name_en = SerializerMethodField(source="type")
ou_nb = SerializerMethodField(source="orgunit")
ou_en = SerializerMethodField(source="orgunit")
max_days = SerializerMethodField(source="type")
def get_name_nb(self, obj):
return obj.type.name_nb
def get_name_en(self, obj):
return obj.type.name_en
def get_ou_nb(self, obj):
return obj.orgunit.name_nb
def get_ou_en(self, obj):
return obj.orgunit.name_en
def get_max_days(self, obj):
return obj.type.max_days
class Meta:
model = Role
fields = [
"id",
"name_nb",
"name_en",
"ou_nb",
"ou_en",
"start_date",
"end_date",
"max_days",
"contact_person_unit",
"comments",
]
read_only_fields = [
"contact_person_unit",
]
......@@ -6,13 +6,12 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from greg.api.serializers.person import SpecialPersonSerializer
from greg.models import Identity, Person
from greg.permissions import IsSponsor
from greg.utils import is_identity_duplicate
from gregui import validation
from gregui.api.serializers.IdentityDuplicateError import IdentityDuplicateError
from gregui.api.serializers.guest import create_identity_or_update
from gregui.api.serializers.guest import GuestSerializer, create_identity_or_update
from gregui.models import GregUserProfile
......@@ -30,7 +29,7 @@ class PersonViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericV
permission_classes = [IsAuthenticated, IsSponsor]
queryset = Person.objects.all()
http_methods = ["get", "patch"]
serializer_class = SpecialPersonSerializer
serializer_class = GuestSerializer
def update(self, request, *args, **kwargs):
"""
......@@ -169,7 +168,7 @@ class GuestInfoViewSet(mixins.ListModelMixin, GenericViewSet):
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated, IsSponsor]
serializer_class = SpecialPersonSerializer
serializer_class = GuestSerializer
def get_queryset(self):
"""
......
from datetime import timedelta
import pytest
from django.conf import settings
from django.utils import timezone
from gregui.api.serializers.guest import GuestSerializer
@pytest.mark.django_db
def test_serialize_guest(invited_person):
person, _ = invited_person
assert GuestSerializer().to_representation(person) == {
"active": False,
"email": "foo@example.org",
"feide_id": None,
"first": "Foo",
"fnr": None,
"invitation_status": "active",
"last": "Bar",
"mobile": None,
"passport": None,
"pid": "1",
"registered": False,
"roles": [
{
"id": 1,
"name_nb": "Role Foo NB",
"name_en": "Role Foo EN",
"ou_nb": "Foo NB",
"ou_en": "Foo EN",
"start_date": None,
"end_date": "2050-10-15",
"max_days": 365,
"contact_person_unit": "",
"comments": "",
},
],
"verified": False,
}
@pytest.mark.django_db
def test_invitation_status(invited_person):
s = GuestSerializer()
person, invitation = invited_person
# there's an active invitation link
assert s.to_representation(person).get("invitation_status") == "active"
# the invitation link has expired
invitation.expire = timezone.now() - timedelta(days=settings.INVITATION_DURATION)
invitation.save()
assert s.to_representation(person).get("invitation_status") == "expired"
# there are no invitation links
invitation.delete()
assert s.to_representation(person).get("invitation_status") == "none"
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