from rest_framework import serializers
from django.db.models import Q
import structlog
from .models import (
PangeaUser,
Organization,
S3ApiKey,
S3Bucket,
SampleGroup,
Sample,
SampleAnalysisResult,
SampleGroupAnalysisResult,
SampleAnalysisResultField,
SampleGroupAnalysisResultField,
Project,
)
logger = structlog.get_logger(__name__)
[docs]class PangeaUserSerializer(serializers.ModelSerializer):
[docs]class OrganizationSerializer(serializers.ModelSerializer):
[docs]class S3BucketSerializer(serializers.ModelSerializer):
[docs]class S3ApiKeySerializer(serializers.ModelSerializer):
[docs]class OrganizationAddUserSerializer(serializers.Serializer):
user = serializers.PrimaryKeyRelatedField(queryset=PangeaUser.objects.all())
[docs]class SampleGroupSerializer(serializers.ModelSerializer):
organization_obj = OrganizationSerializer(source='organization', read_only=True)
[docs]class SampleGroupAddSampleSerializer(serializers.Serializer):
sample_uuid = serializers.UUIDField()
[docs]class ProjectSerializer(serializers.ModelSerializer):
organization_obj = OrganizationSerializer(source='organization', read_only=True)
[docs]class ProjectAddSampleGroupSerializer(serializers.Serializer):
sample_group_uuid = serializers.UUIDField()
[docs]class SampleSerializer(serializers.ModelSerializer):
library_obj = SampleGroupSerializer(source='library.group', read_only=True)
[docs]class SampleAnalysisResultSerializer(serializers.ModelSerializer):
sample_obj = SampleSerializer(source='sample', read_only=True)
[docs]class SampleGroupAnalysisResultSerializer(serializers.ModelSerializer):
sample_group_obj = SampleGroupSerializer(source='sample_group', read_only=True)
[docs]def presign_ar_field_stored_data_if_appropriate(ret, grp):
"""Intercept serialization of an analysis result field to add a presigned URL.
At this point we are assuming the user has permission to access this result.
"""
try:
return _presign_ar_field_stored_data_if_appropriate(ret, grp)
except Exception as e:
# Gracefully fail here. Presigning fail isn't a reason to fail to respond
logger.error(
'presigning_url_failed_during_serialization',
grp_uuid=grp.uuid,
stored_data=ret,
exception=str(e),
)
return ret
def _presign_ar_field_stored_data_if_appropriate(ret, org):
if ret['stored_data'].get('__type__', '').lower() != 's3':
return ret
bucket_name = ret['stored_data']['uri'].split('s3://')[1].split('/')[0]
s3bucket_query = org.s3bucket_set \
.filter(endpoint_url=ret['stored_data']['endpoint_url']) \
.filter(Q(name=bucket_name))
if s3bucket_query.exists():
s3key = s3bucket_query[0].api_key
ret['stored_data']['presigned_url'] = s3key.presign_url(
ret['stored_data']['endpoint_url'],
ret['stored_data']['uri']
)
return ret
[docs]class SampleAnalysisResultFieldSerializer(serializers.ModelSerializer):
analysis_result_obj = SampleAnalysisResultSerializer(source='analysis_result', read_only=True)
[docs] def to_representation(self, instance):
"""Convert `username` to lowercase."""
ret = super().to_representation(instance)
return presign_ar_field_stored_data_if_appropriate(
ret,
instance.analysis_result.sample.organization,
)
[docs]class SampleGroupAnalysisResultFieldSerializer(serializers.ModelSerializer):
analysis_result_obj = SampleGroupAnalysisResultSerializer(source='analysis_result',
read_only=True)
[docs] def to_representation(self, instance):
"""Convert `username` to lowercase."""
ret = super().to_representation(instance)
return presign_ar_field_stored_data_if_appropriate(
ret,
instance.analysis_result.sample_group.organization,
)