class LeadSerializer(RemoveNullFieldsMixin, DynamicFieldsMixin, UserResourceSerializer): """ Lead Model Serializer """ no_of_entries = serializers.IntegerField( read_only=True, ) attachment = SimpleFileSerializer(required=False) classified_doc_id = serializers.IntegerField( source='leadpreview.classified_doc_id', read_only=True, ) assignee_details = SimpleUserSerializer( source='assignee', many=True, read_only=True, ) class Meta: model = Lead fields = ('__all__') # validations def validate_project(self, project): # Make sure we have access to the given project if not project.can_get(self.context['request'].user): raise serializers.ValidationError( 'Invalid project: {}'.format(project.id)) return project
class SimpleEntrySerializer(serializers.ModelSerializer): image_details = SimpleFileSerializer(source='image', read_only=True) tabular_field_data = FieldProcessedOnlySerializer(source='tabular_field') class Meta: model = Entry fields = ('id', 'excerpt', 'dropped_excerpt', 'image', 'image_details', 'entry_type', 'tabular_field', 'tabular_field_data')
def get_gallery_files_details(self, assessment): # Right now gallery files are only used in additional_documents additional_documents = (assessment.metadata or {}).get('additional_documents') if not additional_documents: return files_id = [] for items in additional_documents.values(): for item in items or []: if item.get('id') and item.get('type') == 'file': files_id.append(item['id']) # TODO: qs = File.objects.filter(id__in=files_id).all() return SimpleFileSerializer(qs, context=self.context, many=True).data
class AdminLevelSerializer(RemoveNullFieldsMixin, DynamicFieldsMixin, serializers.ModelSerializer): """ Admin Level Model Serializer """ geo_shape_file_details = SimpleFileSerializer(source='geo_shape_file', read_only=True) geojson_file = URLCachedFileField(required=False, read_only=True) bounds_file = URLCachedFileField(required=False, read_only=True) class Meta: model = AdminLevel exclude = ('geo_area_titles', ) # Validations def validate_region(self, region): if not region.can_modify(self.context['request'].user): raise serializers.ValidationError('Invalid region') return region def create(self, validated_data): admin_level = super().create(validated_data) admin_level.stale_geo_areas = True admin_level.save() region = admin_level.region region.modified_by = self.context['request'].user region.save() if not settings.TESTING: transaction.on_commit(lambda: load_geo_areas.delay(region.id)) return admin_level def update(self, instance, validated_data): admin_level = super().update( instance, validated_data, ) admin_level.stale_geo_areas = True admin_level.save() region = admin_level.region region.modified_by = self.context['request'].user region.save() if not settings.TESTING: transaction.on_commit(lambda: load_geo_areas.delay(region.id)) return admin_level
class EntrySerializer(RemoveNullFieldsMixin, DynamicFieldsMixin, DeprecatedUserResourceSerializer): attributes = ListToDictField( child=SimpleAttributeSerializer(many=True), key='widget', source='attribute_set', required=False, ) project = serializers.PrimaryKeyRelatedField( required=False, queryset=Project.objects.all()) resolved_comment_count = serializers.SerializerMethodField() unresolved_comment_count = serializers.SerializerMethodField() project_labels = serializers.SerializerMethodField() controlled_changed_by_details = SimpleUserSerializer( source='controlled_changed_by', read_only=True, ) image_details = SimpleFileSerializer(source='image', read_only=True) lead_image = serializers.PrimaryKeyRelatedField( required=False, write_only=True, queryset=LeadPreviewImage.objects.all()) # NOTE: Provided by annotate `annotate_comment_count` verified_by_count = serializers.IntegerField(read_only=True) is_verified_by_current_user = serializers.BooleanField(read_only=True) class Meta: model = Entry fields = '__all__' def get_project_labels(self, entry): # Should be provided from view label_count = self.context.get('entry_group_label_count') if label_count is not None: return label_count.get(entry.pk) or [] # Fallback return EntryGroupLabel.get_stat_for_entry(entry.entrygrouplabel_set) def get_resolved_comment_count(self, entry): if hasattr(entry, 'resolved_comment_count'): return entry.resolved_comment_count return entry.entrycomment_set.filter(parent=None, is_resolved=True).count() def get_unresolved_comment_count(self, entry): if hasattr(entry, 'unresolved_comment_count'): return entry.unresolved_comment_count return entry.entrycomment_set.filter(parent=None, is_resolved=False).count() def validate(self, data): """ - Lead image is copied to deep gallery files - Raw image (base64) are saved as deep gallery files """ request = self.context['request'] lead = data.get('lead') or (self.instance and self.instance.lead) image = data.get('image') image_raw = data.pop('image_raw', None) lead_image = data.pop('lead_image', None) # If gallery file is provided make sure user owns the file if image: if ((self.instance and self.instance.image) != image and not image.is_public and image.created_by != self.context['request'].user): raise serializers.ValidationError({ 'image': f'You don\'t have permission to attach image: {image}', }) return data # If lead image is provided make sure lead are same elif lead_image: if lead_image.lead != lead: raise serializers.ValidationError({ 'lead_image': f'You don\'t have permission to attach lead image: {lead_image}', }) data['image'] = lead_image.clone_as_deep_file(request.user) elif image_raw: generated_image = base64_to_deep_image( image_raw, lead, request.user, ) if type(generated_image) == File: data['image'] = generated_image return data def create(self, validated_data): if validated_data.get('project') is None: validated_data['project'] = validated_data['lead'].project return super().create(validated_data) def update(self, instance, validated_data): # once altered, uncontrol the entry if its uncontrolled if instance and instance.controlled: validated_data['controlled'] = False validated_data['controlled_changed_by'] = self.context[ 'request'].user # NOTE: Create a review instance for this action. review_comment = EntryReviewComment.objects.create( entry=instance, created_by=self.context['request'].user, comment_type=EntryReviewComment.CommentType.UNCONTROL, ) review_comment.comment_texts.model.objects.create( comment=review_comment, text='This comment was generated by entry edit action') entry = super().update(instance, validated_data) return entry
class LeadSerializer( RemoveNullFieldsMixin, DynamicFieldsMixin, WriteOnlyOnCreateSerializerMixin, UserResourceSerializer, ): """ Lead Model Serializer """ # annotated in lead.get_for entries_count = serializers.IntegerField(read_only=True) controlled_entries_count = serializers.IntegerField(read_only=True) filtered_entries_count = serializers.IntegerField(read_only=True) controlled_filtered_entries_count = serializers.IntegerField(read_only=True) assessment_id = serializers.IntegerField(read_only=True) priority_display = serializers.CharField(source='get_priority_display', read_only=True) attachment = SimpleFileSerializer(required=False) thumbnail = URLCachedFileField( source='leadpreview.thumbnail', read_only=True, ) thumbnail_height = serializers.IntegerField( source='leadpreview.thumbnail_height', read_only=True, ) thumbnail_width = serializers.IntegerField( source='leadpreview.thumbnail_width', read_only=True, ) word_count = serializers.IntegerField( source='leadpreview.word_count', read_only=True, ) page_count = serializers.IntegerField( source='leadpreview.page_count', read_only=True, ) classified_doc_id = serializers.IntegerField( source='leadpreview.classified_doc_id', read_only=True, ) # TODO: Remove (Legacy) author_detail = SimpleOrganizationSerializer(source='author', read_only=True) authors_detail = SimpleOrganizationSerializer(source='authors', many=True, read_only=True) source_detail = SimpleOrganizationSerializer(source='source', read_only=True) assignee_details = SimpleUserSerializer( source='get_assignee', # many=True, read_only=True, ) assignee = SingleValueThayMayBeListField( source='get_assignee.id', required=False, ) tabular_book = serializers.SerializerMethodField() emm_triggers = LeadEMMTriggerSerializer(many=True, required=False) emm_entities = EMMEntitySerializer(many=True, required=False) # extra fields added from entryleadserializer confidentiality_display = serializers.CharField(source='get_confidentiality_display', read_only=True) class Meta: model = Lead fields = ('__all__') # Legacy Fields read_only_fields = ('author_raw', 'source_raw') write_only_on_create_fields = ['emm_triggers', 'emm_entities'] def get_tabular_book(self, obj): file = obj.attachment if file and hasattr(file, 'book'): return file.book.id return None @staticmethod def add_update__validate(data, instance, attachment=None): project = data.get('project', instance and instance.project) source_type = data.get('source_type', instance and instance.source_type) text = data.get('text', instance and instance.text) url = data.get('url', instance and instance.url) return raise_or_return_existing_lead( project, instance, source_type, url, text, attachment, ) def validate_is_assessment_lead(self, value): # Allow setting True # For False make sure there are no assessment attached. if value is False and hasattr(self.instance, 'assessment'): raise serializers.ValidationError('Lead already has an assessment.') return value def validate(self, data): attachment_id = self.get_initial().get('attachment', {}).get('id') LeadSerializer.add_update__validate( data, self.instance, File.objects.filter(pk=attachment_id).first() ) return data # TODO: Probably also validate assignee to valid list of users def create(self, validated_data): assignee_field = validated_data.pop('get_assignee', None) assignee_id = assignee_field and assignee_field.get('id', None) assignee = assignee_id and get_object_or_404(User, id=assignee_id) emm_triggers = validated_data.pop('emm_triggers', []) emm_entities_names = [ entity['name'] for entity in validated_data.pop('emm_entities', []) if isinstance(entity, dict) and 'name' in entity ] lead = super().create(validated_data) for entity in EMMEntity.objects.filter(name__in=emm_entities_names): lead.emm_entities.add(entity) lead.save() with transaction.atomic(): for trigger in emm_triggers: LeadEMMTrigger.objects.create(**trigger, lead=lead) if assignee: lead.assignee.add(assignee) return lead def update(self, instance, validated_data): assignee_field = validated_data.pop('get_assignee', None) assignee_id = assignee_field and assignee_field.get('id', None) assignee = assignee_id and get_object_or_404(User, id=assignee_id) # We do not update triggers and entities validated_data.pop('emm_entities', None) validated_data.pop('emm_triggers', None) lead = super().update(instance, validated_data) if assignee_field: lead.assignee.clear() if assignee: lead.assignee.add(assignee) return lead
class LeadSerializer(RemoveNullFieldsMixin, DynamicFieldsMixin, ProjectEntitySerializer): """ Lead Model Serializer """ no_of_entries = serializers.IntegerField(read_only=True) attachment = SimpleFileSerializer(required=False) classified_doc_id = serializers.IntegerField( source='leadpreview.classified_doc_id', read_only=True, ) assignee_details = SimpleUserSerializer( source='get_assignee', # many=True, read_only=True, ) assignee = SingleValueThayMayBeListField( source='get_assignee.id', required=False, ) class Meta: model = Lead fields = ('__all__') def validate(self, data): project = data.get('project', self.instance and self.instance.project) source_type = data.get('source_type', self.instance and self.instance.source_type) # For website types, check if url has already been added if source_type == Lead.WEBSITE: url = data.get('url', self.instance and self.instance.url) if check_if_url_exists(url, None, project, self.instance and self.instance.id): raise serializers.ValidationError( 'A lead with this URL has already been added to ' 'this project') return data # TODO: Probably also validate assignee to valid list of users def create(self, validated_data): assignee_field = validated_data.pop('get_assignee', None) assignee_id = assignee_field and assignee_field.get('id', None) assignee = assignee_id and get_object_or_404(User, id=assignee_id) lead = super().create(validated_data) if assignee: lead.assignee.add(assignee) return lead def update(self, instance, validated_data): assignee_field = validated_data.pop('get_assignee', None) assignee_id = assignee_field and assignee_field.get('id', None) assignee = assignee_id and get_object_or_404(User, id=assignee_id) lead = super().update(instance, validated_data) lead.save() if assignee_field: lead.assignee.clear() if assignee: lead.assignee.add(assignee) return lead