Skip to content

Commit

Permalink
Adjust serializer inheritance scheme for upgraded DRF
Browse files Browse the repository at this point in the history
Co-authored-by: John Tordoff <johnetordoff@gmail.com>
  • Loading branch information
2 people authored and cslzchen committed Sep 9, 2022
1 parent 9e9c487 commit 51ba98e
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 23 deletions.
2 changes: 1 addition & 1 deletion api/base/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

def get_resource_object_member(error_key, context):
from api.base.serializers import RelationshipField
field = context['view'].serializer_class._declared_fields.get(error_key, None)
field = context['view'].get_serializer_class()._declared_fields.get(error_key, None)
if field:
return 'relationships' if isinstance(field, RelationshipField) else 'attributes'
# If field cannot be found (where read/write operations have different serializers,
Expand Down
21 changes: 19 additions & 2 deletions api/draft_registrations/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,19 @@
NodeContributorsSerializer,
NodeContributorsCreateSerializer,
NodeContributorDetailSerializer,
RegistrationSchemaRelationshipField,
)

from api.taxonomies.serializers import TaxonomizableSerializerMixin
from osf.exceptions import DraftRegistrationStateError
from osf.models import Node
from website import settings


class NodeRelationshipField(RelationshipField):

def to_internal_value(self, node_id):
node = self.context['view'].get_node(node_id=node_id) if node_id else None
return {'branched_from': node}
return {'branched_from': Node.load(node_id)}


class DraftRegistrationSerializer(DraftRegistrationLegacySerializer, TaxonomizableSerializerMixin):
Expand All @@ -46,6 +48,13 @@ class DraftRegistrationSerializer(DraftRegistrationLegacySerializer, Taxonomizab
tags = ValuesListField(attr_name='name', child=ser.CharField(), required=False)
node_license = NodeLicenseSerializer(required=False, source='license')

registration_schema = RegistrationSchemaRelationshipField(
related_view='schemas:registration-schema-detail',
related_view_kwargs={'schema_id': '<registration_schema._id>'},
required=True,
read_only=False,
)

links = LinksField({
'self': 'get_absolute_url',
})
Expand Down Expand Up @@ -142,6 +151,7 @@ class DraftRegistrationDetailSerializer(DraftRegistrationSerializer, DraftRegist
Overrides DraftRegistrationLegacySerializer to make id required.
registration_supplement, node, cannot be changed after draft has been created.
"""
id = IDField(source='_id', required=True)

links = LinksField({
'self': 'get_self_url',
Expand All @@ -156,6 +166,13 @@ def get_self_url(self, obj):
},
)

registration_schema = RegistrationSchemaRelationshipField(
related_view='schemas:registration-schema-detail',
related_view_kwargs={'schema_id': '<registration_schema._id>'},
required=False,
read_only=False,
)

def update(self, draft, validated_data):
draft = super(DraftRegistrationDetailSerializer, self).update(draft, validated_data)
user = self.context['request'].user
Expand Down
14 changes: 3 additions & 11 deletions api/files/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@

from rest_framework import generics
from rest_framework import permissions as drf_permissions
from rest_framework.exceptions import NotFound, PermissionDenied, ValidationError
from rest_framework.exceptions import NotFound, ValidationError

from framework.auth.oauth_scopes import CoreScopes

from osf.models import (
Guid,
BaseFileNode,
FileVersion,
QuickFilesNode,
)

from api.base.exceptions import Gone
Expand All @@ -29,7 +28,7 @@
from api.files.permissions import CheckedOutOrAdmin
from api.files.permissions import FileMetadataRecordPermission
from api.files.serializers import FileSerializer
from api.files.serializers import FileDetailSerializer, QuickFilesDetailSerializer
from api.files.serializers import FileDetailSerializer
from api.files.serializers import FileMetadataRecordSerializer
from api.files.serializers import FileVersionSerializer
from osf.utils.permissions import ADMIN
Expand Down Expand Up @@ -86,14 +85,7 @@ class FileDetail(JSONAPIBaseView, generics.RetrieveUpdateAPIView, FileMixin):
view_name = 'file-detail'

def get_serializer_class(self):
try:
target = self.get_target()
except (NotFound, Gone, PermissionDenied):
return FileDetailSerializer
else:
if isinstance(target, QuickFilesNode):
return QuickFilesDetailSerializer
return FileDetailSerializer
return FileDetailSerializer

def get_target(self):
return self.get_file().target
Expand Down
40 changes: 31 additions & 9 deletions api/nodes/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
WaterbutlerLink, relationship_diff, BaseAPISerializer,
HideIfWikiDisabled, ShowIfAdminScopeOrAnonymous,
ValuesListField, TargetField,

)
from api.base.settings import ADDONS_FOLDER_CONFIGURABLE
from api.base.utils import (
Expand Down Expand Up @@ -222,6 +223,17 @@ def get_license_details(node, validated_data):
'copyrightHolders': license_holders,
}


class RegistrationSchemaRelationshipField(RelationshipField):

def to_internal_value(self, registration_schema_id):
schema = get_object_or_error(RegistrationSchema, registration_schema_id, self.context['request'])
latest_version = RegistrationSchema.objects.get_latest_version(schema.name).schema_version
if latest_version != schema.schema_version or not schema.active:
raise exceptions.ValidationError('Registration supplement must be an active schema.')
return {'registration_schema': schema}


class NodeSerializer(TaxonomizableSerializerMixin, JSONAPISerializer):
# TODO: If we have to redo this implementation in any of the other serializers, subclass ChoiceField and make it
# handle blank choices properly. Currently DRF ChoiceFields ignore blank options, which is incorrect in this
Expand Down Expand Up @@ -314,6 +326,12 @@ class NodeSerializer(TaxonomizableSerializerMixin, JSONAPISerializer):
tags = ValuesListField(attr_name='name', child=ser.CharField(), required=False)
access_requests_enabled = ShowIfVersion(ser.BooleanField(read_only=False, required=False), min_version='2.0', max_version='2.8')
node_license = NodeLicenseSerializer(required=False, source='license')
registration_schema = RegistrationSchemaRelationshipField(
related_view='schemas:registration-schema-detail',
related_view_kwargs={'schema_id': '<registration_schema._id>'},
required=False,
read_only=False,
)
analytics_key = ShowIfAdminScopeOrAnonymous(ser.CharField(read_only=True, source='keenio_read_key'))
template_from = ser.CharField(
required=False, allow_blank=False, allow_null=False,
Expand Down Expand Up @@ -1501,15 +1519,6 @@ def create(self, validated_data):

return self.make_instance_obj(node)

class RegistrationSchemaRelationshipField(RelationshipField):

def to_internal_value(self, registration_schema_id):
schema = get_object_or_error(RegistrationSchema, registration_schema_id, self.context['request'])
latest_version = RegistrationSchema.objects.get_latest_version(schema.name).schema_version
if latest_version != schema.schema_version or not schema.active:
raise exceptions.ValidationError('Registration supplement must be an active schema.')
return {'registration_schema': schema}


class DraftRegistrationLegacySerializer(JSONAPISerializer):

Expand Down Expand Up @@ -1590,6 +1599,19 @@ def get_node(self, validated_data=None):
def create(self, validated_data):
initiator = get_user_auth(self.context['request']).user
node = self.get_node(validated_data)
branched_from_guid = self.context['request'].data.get('branched_from')
if not node and branched_from_guid:
node = get_object_or_error(Node, branched_from_guid, self.context['request'])
if not node.has_permission(initiator, 'write'):
raise exceptions.NotFound()

if node and node.is_deleted:
from api.base.exceptions import Gone
raise Gone(detail='The requested node is no longer available.')

if node and not node.has_permission(initiator, 'write'):
raise exceptions.PermissionDenied()

# Old workflow - deeply nested
metadata = validated_data.pop('registration_metadata', None)
registration_responses = validated_data.pop('registration_responses', None)
Expand Down

0 comments on commit 51ba98e

Please sign in to comment.