from rest_framework import serializers from rest_framework.exceptions import PermissionDenied from glitchtip.exceptions import ConflictException from projects.serializers.serializers import OrganizationProjectSerializer from teams.models import Team from teams.serializers import TeamSerializer from users.models import User from users.serializers import UserSerializer from users.utils import is_user_registration_open from ..models import ROLES, OrganizationUser, OrganizationUserRole from .base_serializers import OrganizationReferenceSerializer class OrganizationSerializer(OrganizationReferenceSerializer): pass class OrganizationDetailSerializer(OrganizationSerializer): projects = OrganizationProjectSerializer(many=True) teams = TeamSerializer(many=True) openMembership = serializers.BooleanField(source="open_membership") scrubIPAddresses = serializers.BooleanField(source="scrub_ip_addresses") class Meta(OrganizationSerializer.Meta): fields = OrganizationSerializer.Meta.fields + ( "projects", "openMembership", "scrubIPAddresses", "teams", ) class OrganizationUserSerializer(serializers.ModelSerializer): user = UserSerializer(required=False, read_only=True) role = serializers.CharField(source="get_role") roleName = serializers.CharField(source="get_role_display", read_only=True) dateCreated = serializers.DateTimeField(source="created", read_only=True) teams = serializers.SlugRelatedField( many=True, write_only=True, slug_field="slug", queryset=Team.objects.none() ) isOwner = serializers.SerializerMethodField() class Meta: model = OrganizationUser fields = ( "role", "id", "user", "roleName", "dateCreated", "email", "teams", "pending", "isOwner", ) def __init__(self, *args, request_user=None, **kwargs): super().__init__(*args, **kwargs) if "request" in self.context: organization_slug = self.context["view"].kwargs.get("organization_slug") self.fields["teams"].child_relation.queryset = Team.objects.filter( organization__slug=organization_slug ) def get_extra_kwargs(self): """email should be read only when updating""" extra_kwargs = super().get_extra_kwargs() if self.instance is not None: extra_kwargs["email"] = {"read_only": True} extra_kwargs["user"] = {"read_only": True} return extra_kwargs def get_isOwner(self, obj): if owner := obj.organization.owner: return owner.organization_user_id == obj.id return False def create(self, validated_data): role = OrganizationUserRole.from_string(validated_data.get("get_role")) email = validated_data.get("email") organization = validated_data.get("organization") teams = validated_data.get("teams") if ( not is_user_registration_open() and not User.objects.filter(email=email).exists() ): raise PermissionDenied("Only existing users may be invited") if organization.organization_users.filter(email=email).exists(): raise ConflictException(f"The user {email} is already invited", "email") if organization.organization_users.filter(user__email=email).exists(): raise ConflictException(f"The user {email} is already a member", "email") org_user = super().create( {"role": role, "email": email, "organization": organization} ) org_user.team_set.add(*teams) return org_user def update(self, instance, validated_data): get_role = validated_data.pop("get_role", None) if get_role: role = OrganizationUserRole.from_string(get_role) validated_data["role"] = role return super().update(instance, validated_data) def to_representation(self, obj): """Override email for representation to potentially show user's email""" self.fields["email"] = serializers.SerializerMethodField() return super().to_representation(obj) def get_email(self, obj): """Prefer user primary email over org user email (which is only for invites)""" if obj.user: return obj.user.email return obj.email class OrganizationUserDetailSerializer(OrganizationUserSerializer): teams = serializers.SlugRelatedField( source="team_set", slug_field="slug", read_only=True, many=True ) roles = serializers.SerializerMethodField() class Meta(OrganizationUserSerializer.Meta): fields = OrganizationUserSerializer.Meta.fields + ("roles",) def get_roles(self, obj): return ROLES class OrganizationUserProjectsSerializer(OrganizationUserSerializer): projects = serializers.SerializerMethodField() class Meta(OrganizationUserSerializer.Meta): fields = OrganizationUserSerializer.Meta.fields + ("projects",) def get_projects(self, obj): return obj.organization.projects.filter(team__members=obj).values_list( "slug", flat=True ) class ReinviteSerializer(serializers.Serializer): reinvite = serializers.IntegerField() def update(self, instance, validated_data): if validated_data.get("reinvite"): pass # Send email return instance class OrganizationUserOrganizationSerializer(OrganizationUserSerializer): """Organization User Serializer with Organization info""" organization = OrganizationSerializer() class Meta(OrganizationUserSerializer.Meta): fields = OrganizationUserSerializer.Meta.fields + ("organization",) class AcceptInviteSerializer(serializers.Serializer): accept_invite = serializers.BooleanField() org_user = OrganizationUserOrganizationSerializer(read_only=True)