Files

120 lines
4.5 KiB
Python
Raw Permalink Normal View History

"""Read-only serializers for profile payloads."""
from __future__ import annotations
from typing import Any
from rest_framework import serializers
from apps.profiles.models import Company, Education, Experience, Profile, School, Skill
from apps.profiles.privacy import mask_emails, mask_phones
class SkillSerializer(serializers.ModelSerializer):
class Meta:
model = Skill
fields = ("id", "name", "slug", "profile_count")
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ("id", "name", "industry", "size", "founded", "website", "location_name")
class SchoolSerializer(serializers.ModelSerializer):
class Meta:
model = School
fields = ("id", "name", "type", "location_name")
class ExperienceSerializer(serializers.ModelSerializer):
company = CompanySerializer(read_only=True)
class Meta:
model = Experience
fields = (
"id", "title", "title_role", "title_sub_role", "levels", "company", "company_name",
"start_date", "end_date", "start_year", "end_year", "is_primary", "location_name",
"summary",
) # fmt: skip
class EducationSerializer(serializers.ModelSerializer):
school = SchoolSerializer(read_only=True)
class Meta:
model = Education
fields = (
"id", "school", "school_name", "degrees", "majors", "minors", "gpa",
"start_date", "end_date", "end_year",
) # fmt: skip
class PIIMixin:
"""Masks contact details unless the caller is allowed to see them."""
def _can_view_pii(self) -> bool:
request = self.context.get("request") # type: ignore[attr-defined]
user = getattr(request, "user", None)
return bool(user and user.is_authenticated and user.can_view_pii)
def get_emails(self, obj: Profile) -> list[dict[str, str]]:
return obj.emails if self._can_view_pii() else mask_emails(obj.emails)
def get_phone_numbers(self, obj: Profile) -> list[str]:
return obj.phone_numbers if self._can_view_pii() else mask_phones(obj.phone_numbers)
class ProfileListSerializer(PIIMixin, serializers.ModelSerializer):
"""Compact representation used for result cards."""
headline = serializers.CharField(read_only=True)
company = serializers.CharField(source="current_company.name", default="", read_only=True)
skills = serializers.SerializerMethodField()
emails = serializers.SerializerMethodField()
class Meta:
model = Profile
fields = (
"id", "full_name", "headline", "job_title", "job_title_role", "seniority_levels",
"company", "industry", "location_name", "location_country", "years_experience",
"linkedin_url", "skills", "emails",
) # fmt: skip
def get_skills(self, obj: Profile) -> list[str]:
# ``prefetch_related`` in the view keeps this at one extra query total.
return [link.skill.name for link in obj.profile_skills.all()[:10]]
class ProfileDetailSerializer(PIIMixin, serializers.ModelSerializer):
headline = serializers.CharField(read_only=True)
current_company = CompanySerializer(read_only=True)
skills = serializers.SerializerMethodField()
experiences = ExperienceSerializer(many=True, read_only=True)
educations = EducationSerializer(many=True, read_only=True)
emails = serializers.SerializerMethodField()
phone_numbers = serializers.SerializerMethodField()
pii_masked = serializers.SerializerMethodField()
class Meta:
model = Profile
fields = (
"id", "external_id", "full_name", "first_name", "last_name", "gender", "headline",
"job_title", "job_title_role", "job_title_sub_role", "seniority_levels",
"current_company", "industry", "job_summary", "job_start_date",
"location_name", "location_locality", "location_region", "location_country",
"location_continent", "summary", "years_experience", "inferred_salary",
"connections", "interests", "languages", "linkedin_url", "linkedin_username",
"github_url", "twitter_url", "skills", "experiences", "educations",
"emails", "phone_numbers", "pii_masked",
) # fmt: skip
def get_skills(self, obj: Profile) -> list[dict[str, Any]]:
return [
{"name": link.skill.name, "slug": link.skill.slug} for link in obj.profile_skills.all()
]
def get_pii_masked(self, obj: Profile) -> bool: # noqa: ARG002
return not self._can_view_pii()