def get_subjects(self, obj): from api.taxonomies.serializers import TaxonomyField return [ [ TaxonomyField().to_representation(subj) for subj in hier ] for hier in obj.subject_hierarchy ]
class TaxonomySerializer(JSONAPISerializer): filterable_fields = frozenset([ 'text', 'parents', 'parent', 'id', ]) id = ser.CharField(source='_id', required=True) text = ser.CharField(max_length=200) parents = ShowIfVersion( ser.SerializerMethodField(), min_version='2.0', max_version='2.3', ) parent = TaxonomyField() child_count = ser.SerializerMethodField() share_title = ser.CharField(source='provider.share_title', read_only=True) path = ser.CharField(read_only=True) links = LinksField({ 'parents': 'get_parent_urls', 'self': 'get_absolute_url', }) def get_child_count(self, obj): children_count = getattr(obj, 'children_count', None) return children_count if children_count is not None else obj.child_count def get_parents(self, obj): if not obj.parent: return [] return [TaxonomyField().to_representation(obj.parent)] def get_parent_urls(self, obj): if obj.parent: return [obj.parent.get_absolute_url()] return [] def get_absolute_url(self, obj): return obj.get_absolute_url() class Meta: type_ = 'taxonomies'
class PreprintSerializer(JSONAPISerializer): filterable_fields = frozenset([ 'id', 'date_created', 'date_modified', 'date_published', 'provider', 'is_published', ]) id = IDField(source='_id', read_only=True) subjects = JSONAPIListField(child=JSONAPIListField(child=TaxonomyField()), allow_null=True, required=False) date_created = DateByVersion(read_only=True) date_modified = DateByVersion(read_only=True) date_published = DateByVersion(read_only=True) doi = ser.CharField(source='article_doi', required=False, allow_null=True) is_published = ser.BooleanField(required=False) is_preprint_orphan = ser.BooleanField(read_only=True) license_record = NodeLicenseSerializer(required=False, source='license') node = NodeRelationshipField(related_view='nodes:node-detail', related_view_kwargs={'node_id': '<node._id>'}, read_only=False) license = PreprintLicenseRelationshipField( related_view='licenses:license-detail', related_view_kwargs={'license_id': '<license.node_license._id>'}, read_only=False) provider = PreprintProviderRelationshipField( related_view='preprint_providers:preprint_provider-detail', related_view_kwargs={'provider_id': '<provider._id>'}, read_only=False) primary_file = PrimaryFileRelationshipField( related_view='files:file-detail', related_view_kwargs={'file_id': '<primary_file._id>'}, lookup_url_kwarg='file_id', read_only=False) links = LinksField({ 'self': 'get_preprint_url', 'html': 'get_absolute_html_url', 'doi': 'get_doi_url' }) class Meta: type_ = 'preprints' def get_preprint_url(self, obj): return absolute_reverse( 'preprints:preprint-detail', kwargs={ 'preprint_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'] }) def get_absolute_url(self, obj): return self.get_preprint_url(obj) def get_doi_url(self, obj): return 'https://dx.doi.org/{}'.format( obj.article_doi) if obj.article_doi else None def update(self, preprint, validated_data): assert isinstance( preprint, PreprintService), 'You must specify a valid preprint to be updated' assert isinstance( preprint.node, Node ), 'You must specify a preprint with a valid node to be updated.' auth = get_user_auth(self.context['request']) if not preprint.node.has_permission(auth.user, 'admin'): raise exceptions.PermissionDenied( detail='User must be an admin to update a preprint.') save_node = False save_preprint = False recently_published = False primary_file = validated_data.pop('primary_file', None) if primary_file: self.set_field(preprint.set_primary_file, primary_file, auth) save_node = True if 'subjects' in validated_data: subjects = validated_data.pop('subjects', None) self.set_field(preprint.set_subjects, subjects, auth) save_preprint = True if 'article_doi' in validated_data: preprint.node.preprint_article_doi = validated_data['article_doi'] save_node = True published = validated_data.pop('is_published', None) if published is not None: self.set_field(preprint.set_published, published, auth) save_preprint = True recently_published = published if 'license_type' in validated_data or 'license' in validated_data: license_details = get_license_details(preprint, validated_data) self.set_field(preprint.set_preprint_license, license_details, auth) save_preprint = True if save_node: try: preprint.node.save() except ValidationValueError as e: # Raised from invalid DOI raise exceptions.ValidationError(detail=e.message) if save_preprint: preprint.save() # Send preprint confirmation email signal to new authors on preprint! -- only when published # TODO: Some more thought might be required on this; preprints made from existing # nodes will send emails making it seem like a new node. if recently_published: for author in preprint.node.contributors: if author != auth.user: project_signals.contributor_added.send( preprint.node, contributor=author, auth=auth, email_template='preprint') return preprint def set_field(self, func, val, auth, save=False): try: func(val, auth, save=save) except PermissionsError as e: raise exceptions.PermissionDenied(detail=e.message) except ValueError as e: raise exceptions.ValidationError(detail=e.message) except NodeStateError as e: raise exceptions.ValidationError(detail=e.message)
def get_subjects(self, obj): return [[TaxonomyField().to_representation(subj) for subj in hier] for hier in obj.subject_hierarchy]
def get_parents(self, obj): if not obj.parent: return [] return [TaxonomyField().to_representation(obj.parent)]
class PreprintSerializer(JSONAPISerializer): filterable_fields = frozenset([ 'id', 'title', 'tags', 'date_created', 'date_modified', 'contributors', 'subjects', 'doi' ]) title = ser.CharField(required=False) subjects = JSONAPIListField(child=TaxonomyField(), required=False, source='preprint_subjects') provider = ser.CharField(source='preprint_provider', required=False) date_created = ser.DateTimeField(read_only=True, source='preprint_created') date_modified = ser.DateTimeField(read_only=True) id = IDField(source='_id', required=False) abstract = ser.CharField(source='description', required=False) tags = JSONAPIListField(child=NodeTagField(), required=False) doi = ser.CharField(source='preprint_doi', required=False) primary_file = PrimaryFileRelationshipField( related_view='files:file-detail', related_view_kwargs={'file_id': '<preprint_file._id>'}, lookup_url_kwarg='file_id', read_only=False) files = RelationshipField(related_view='nodes:node-providers', related_view_kwargs={'node_id': '<pk>'}) providers = RelationshipField( related_view='preprints:preprint-preprint_providers', related_view_kwargs={'node_id': '<pk>'}, self_view='preprints:preprint-relationships-preprint_providers', self_view_kwargs={'node_id': '<pk>'}) links = LinksField({ 'self': 'get_preprint_url', 'html': 'get_absolute_html_url', 'doi': 'get_doi_url' }) contributors = RelationshipField( related_view='nodes:node-contributors', related_view_kwargs={'node_id': '<pk>'}, related_meta={'count': 'get_contrib_count'}, ) class Meta: type_ = 'preprints' def get_preprint_url(self, obj): return absolute_reverse('preprints:preprint-detail', kwargs={'node_id': obj._id}) def get_absolute_url(self, obj): return self.get_preprint_url(obj) def get_doi_url(self, obj): return 'https://dx.doi.org/{}'.format( obj.preprint_doi) if obj.preprint_doi else None def create(self, validated_data): node = Node.load(validated_data.pop('_id', None)) if not node: raise exceptions.NotFound('Unable to find Node with specified id.') auth = get_user_auth(self.context['request']) if not node.has_permission(auth.user, permissions.ADMIN): raise exceptions.PermissionDenied if node.is_preprint: raise Conflict( 'This node already stored as a preprint, use the update method instead.' ) primary_file = validated_data.pop('primary_file', None) if not primary_file: raise exceptions.ValidationError( detail='You must specify a primary_file to create a preprint.') self.set_node_field(node.set_preprint_file, primary_file, auth) subjects = validated_data.pop('preprint_subjects', None) if not subjects: raise exceptions.ValidationError( detail= 'You must specify at least one subject to create a preprint.') self.set_node_field(node.set_preprint_subjects, subjects, auth) tags = validated_data.pop('tags', None) if tags: for tag in tags: node.add_tag(tag, auth, save=False, log=False) for key, value in validated_data.iteritems(): setattr(node, key, value) try: node.save() except ValidationValueError as e: raise exceptions.ValidationError(detail=e.message) # Send preprint confirmation email signal to new authors on preprint! for author in node.contributors: if author != auth.user: project_signals.contributor_added.send( node, contributor=author, auth=auth, email_template='preprint') return node def update(self, node, validated_data): from website.models import Node assert isinstance(node, Node), 'You must specify a valid node to be updated.' auth = get_user_auth(self.context['request']) primary_file = validated_data.pop('primary_file', None) if primary_file: self.set_node_field(node.set_preprint_file, primary_file, auth) subjects = validated_data.pop('preprint_subjects', None) if subjects: self.set_node_field(node.set_preprint_subjects, subjects, auth) old_tags = set([tag._id for tag in node.tags]) if 'tags' in validated_data: current_tags = set(validated_data.pop('tags', [])) elif self.partial: current_tags = set(old_tags) else: current_tags = set() for new_tag in (current_tags - old_tags): node.add_tag(new_tag, auth=auth) for deleted_tag in (old_tags - current_tags): node.remove_tag(deleted_tag, auth=auth) for key, value in validated_data.iteritems(): setattr(node, key, value) try: node.save() except ValidationValueError as e: raise exceptions.ValidationError(detail=e.message) return node def set_node_field(self, func, val, auth): try: func(val, auth, save=False) except PermissionsError: raise exceptions.PermissionDenied( 'Not authorized to update this node.') except ValueError as e: raise exceptions.ValidationError(detail=e.message)