Skip to content
Snippets Groups Projects
  • Andreas Ellewsen's avatar
    701afd23
    Add role adding page to guest profiles · 701afd23
    Andreas Ellewsen authored
    Code for guest routes moved to their own folder so that we don't need
    multiple api calls.
    Serializer class for roles has been simplified with methods for
    validation of each field and a separate one used in invites without
    requiring the person field.
    
    Resolves: GREG-61
    Add role adding page to guest profiles
    Andreas Ellewsen authored
    Code for guest routes moved to their own folder so that we don't need
    multiple api calls.
    Serializer class for roles has been simplified with methods for
    validation of each field and a separate one used in invites without
    requiring the person field.
    
    Resolves: GREG-61
role.py 3.89 KiB
import datetime
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.validators import UniqueTogetherValidator

from greg.models import Role


class RoleSerializerUi(serializers.ModelSerializer):
    """Serializer for the Role model with validation of various fields"""

    class Meta:
        model = Role
        fields = [
            "orgunit",
            "start_date",
            "type",
            "end_date",
            "contact_person_unit",
            "comments",
            "available_in_search",
            "person",
        ]
        validators = [
            UniqueTogetherValidator(
                queryset=Role.objects.all(),
                fields=["person", "type", "orgunit", "start_date", "end_date"],
            )
        ]

    def validate_start_date(self, start_date):
        today = datetime.date.today()
        # New start dates cannot be in the past
        if start_date < today:
            raise serializers.ValidationError("Start date cannot be in the past")

        return start_date

    def validate_end_date(self, end_date):
        """Ensure rules for end_date are followed"""
        today = datetime.date.today()
        if end_date < today:
            raise serializers.ValidationError("End date cannot be in the past")
        if self.instance and self.instance.end_date < today:
            raise serializers.ValidationError("Role has ended, cannot change end date")
        return end_date

    def validate_orgunit(self, unit):
        """Enforce rules related to orgunit"""
        sponsor = self.context["sponsor"]
        units = sponsor.units.all()
        # Restrict to a sponsor's own units
        if not units or unit not in units:
            raise ValidationError(
                "A sponsor can only make changes to roles at units they are sponsors for."
            )
        # If we are updating an existing roles, we must be the sponsor of the role
        if self.instance and self.instance.sponsor != sponsor:
            raise ValidationError("You can only edit your own roles.")
        return unit

    def validate(self, attrs):
        """Validate things that need access to multiple fields"""
        # Ensure end date is not further into the future than the role type allows
        today = datetime.date.today()
        if self.instance:
            max_days = today + datetime.timedelta(days=self.instance.type.max_days)
        else:
            max_days = today + datetime.timedelta(days=attrs["type"].max_days)
        if attrs["end_date"] > max_days:
            raise serializers.ValidationError(
                f"New end date too far into the future for this type. Must be before {max_days.strftime('%Y-%m-%d')}"
            )
        # Ensure end date is after start date if start date is set
        if self.instance:
            start_date = attrs.get("start_date") or self.instance.start_date
            end_date = attrs.get("end_date") or self.instance.end_date
            if start_date and end_date < start_date:
                raise serializers.ValidationError(
                    "End date cannot be before start date."
                )
        else:
            if attrs.get("start_date") and attrs["end_date"] < attrs["start_date"]:
                raise serializers.ValidationError(
                    "End date cannot be before start date."
                )
        return attrs


class InviteRoleSerializerUi(RoleSerializerUi):
    """
    Serializer for the role part of an invite.

    This one exists so that we don't have to specify the person argument on the role.
    Simply reuses all the logic of the parent class except requiring the person field.
    """

    class Meta:
        model = Role
        fields = [
            "orgunit",
            "start_date",
            "type",
            "end_date",
            "contact_person_unit",
            "comments",
            "available_in_search",
        ]