From 8a58a5c1314c09891f5394e10ec9e975f1a007e1 Mon Sep 17 00:00:00 2001 From: sudan45 Date: Thu, 6 Jun 2024 23:56:21 +0545 Subject: [PATCH] Add LeadreviewAttachment Model --- .../entry_images_v2/migrate.py | 4 +- apps/commons/receivers.py | 4 +- apps/deepl_integration/handlers.py | 59 ++++++++++++++----- apps/deepl_integration/serializers.py | 22 +++++-- apps/entry/serializers.py | 6 +- apps/entry/tests/test_apis.py | 6 +- apps/lead/admin.py | 8 +-- apps/lead/dataloaders.py | 15 ++++- apps/lead/enums.py | 1 + apps/lead/factories.py | 6 +- .../migrations/0050_auto_20240606_0608.py | 29 +++++++++ apps/lead/models.py | 15 ++++- apps/lead/schema.py | 22 ++++++- apps/lead/serializers.py | 16 ++--- apps/lead/tests/test_apis.py | 19 ++++-- apps/lead/tests/test_mutations.py | 4 +- apps/lead/views.py | 4 +- schema.graphql | 15 +++++ 18 files changed, 198 insertions(+), 57 deletions(-) create mode 100644 apps/lead/migrations/0050_auto_20240606_0608.py diff --git a/apps/bulk_data_migration/entry_images_v2/migrate.py b/apps/bulk_data_migration/entry_images_v2/migrate.py index 8a456902a5..56db783f35 100644 --- a/apps/bulk_data_migration/entry_images_v2/migrate.py +++ b/apps/bulk_data_migration/entry_images_v2/migrate.py @@ -3,7 +3,7 @@ from utils.common import parse_number -from lead.models import LeadPreviewImage +from lead.models import LeadPreviewAttachment from entry.models import Entry from gallery.models import File @@ -34,7 +34,7 @@ def _get_file_from_s3_url(entry, string): return # NOTE: For lead-preview generate gallery files if file_path.startswith('lead-preview/'): - lead_preview = LeadPreviewImage.objects.filter(file=file_path).first() + lead_preview = LeadPreviewAttachment.objects.filter(file=file_path).first() if lead_preview and lead_preview.file and lead_preview.file.storage.exists(lead_preview.file.name): return lead_preview.clone_as_deep_file(entry.created_by) return diff --git a/apps/commons/receivers.py b/apps/commons/receivers.py index 0ee99c8411..088ce696d3 100644 --- a/apps/commons/receivers.py +++ b/apps/commons/receivers.py @@ -5,14 +5,14 @@ from lead.models import ( LeadPreview, - LeadPreviewImage, + LeadPreviewAttachment, ) from unified_connector.models import ConnectorLeadPreviewImage # Lead @receiver(models.signals.post_delete, sender=LeadPreview) -@receiver(models.signals.post_delete, sender=LeadPreviewImage) +@receiver(models.signals.post_delete, sender=LeadPreviewAttachment) # Unified Connector @receiver(models.signals.post_delete, sender=ConnectorLeadPreviewImage) def cleanup_file_on_instance_delete(sender, instance, **kwargs): diff --git a/apps/deepl_integration/handlers.py b/apps/deepl_integration/handlers.py index 031a5f3d63..5cb5ee4223 100644 --- a/apps/deepl_integration/handlers.py +++ b/apps/deepl_integration/handlers.py @@ -37,7 +37,7 @@ from lead.models import ( Lead, LeadPreview, - LeadPreviewImage, + LeadPreviewAttachment, ) from lead.typings import NlpExtractorDocument from entry.models import Entry @@ -636,13 +636,14 @@ def trigger_lead_extract(cls, lead, task_instance=None): def save_data( lead: Lead, text_source_uri: str, - images_uri: List[str], + images_uri: List[dict], + table_uri: List[dict], word_count: int, page_count: int, text_extraction_id: str, ): LeadPreview.objects.filter(lead=lead).delete() - LeadPreviewImage.objects.filter(lead=lead).delete() + LeadPreviewAttachment.objects.filter(lead=lead).delete() # and create new one LeadPreview.objects.create( lead=lead, @@ -651,18 +652,44 @@ def save_data( page_count=page_count, text_extraction_id=text_extraction_id, ) - # Save extracted images as LeadPreviewImage instances + # Save extracted images as LeadPreviewAttachment instances # TODO: The logic is same for unified_connector leads as well. Maybe have a single func? - image_base_path = f'{lead.pk}' - for image_uri in images_uri: - lead_image = LeadPreviewImage(lead=lead) - image_obj = RequestHelper(url=image_uri, ignore_error=True).get_file() - if image_obj: - lead_image.file.save( - os.path.join(image_base_path, os.path.basename(urlparse(image_uri).path)), - image_obj + + attachement_base_path = f'{lead.pk}' + images = [dict(item) for item in images_uri] + for image_uri in images: + for image in image_uri['images']: + lead_attachement = LeadPreviewAttachment(lead=lead) + image_obj = RequestHelper(url=image, ignore_error=True).get_file() + if image_obj: + lead_attachement.file.save( + os.path.join(attachement_base_path, os.path.basename(urlparse(image).path)), + image_obj + ) + lead_attachement.page_number = image_uri['page_number'] + lead_attachement.type = LeadPreviewAttachment.AttachementFileType.IMAGE + lead_attachement.file_preview = lead_attachement.file + + lead_attachement.save() + + table_path = [dict(item) for item in table_uri] + for table in table_path: + lead_attachement = LeadPreviewAttachment(lead=lead) + table_img = RequestHelper(url=table['image_link'], ignore_error=True).get_file() + table_attahcment = RequestHelper(url=table['content_link'], ignore_error=True).get_file() + if table_img: + lead_attachement.file_preview.save( + os.path.join(attachement_base_path, os.path.basename(urlparse(table['image_link']).path)), + table_img ) - lead_image.save() + lead_attachement.page_number = table['page_number'] + lead_attachement.type = LeadPreviewAttachment.AttachementFileType.XLSX + lead_attachement.file.save( + os.path.join(attachement_base_path, os.path.basename(urlparse(table['content_link']).path)), + table_attahcment + ) + lead_attachement.save() + lead.update_extraction_status(Lead.ExtractionStatus.SUCCESS) return lead @@ -674,7 +701,7 @@ def save_lead_data_using_connector_lead( if connector_lead.extraction_status != ConnectorLead.ExtractionStatus.SUCCESS: return False LeadPreview.objects.filter(lead=lead).delete() - LeadPreviewImage.objects.filter(lead=lead).delete() + LeadPreviewAttachment.objects.filter(lead=lead).delete() # and create new one LeadPreview.objects.create( lead=lead, @@ -683,10 +710,10 @@ def save_lead_data_using_connector_lead( page_count=connector_lead.page_count, text_extraction_id=connector_lead.text_extraction_id, ) - # Save extracted images as LeadPreviewImage instances + # Save extracted images as LeadPreviewAttachment instances # TODO: The logic is same for unified_connector leads as well. Maybe have a single func? for connector_lead_preview_image in connector_lead.preview_images.all(): - lead_image = LeadPreviewImage(lead=lead) + lead_image = LeadPreviewAttachment(lead=lead) lead_image.file.save( connector_lead_preview_image.image.name, connector_lead_preview_image.image, diff --git a/apps/deepl_integration/serializers.py b/apps/deepl_integration/serializers.py index c4d9f98d15..203701e542 100644 --- a/apps/deepl_integration/serializers.py +++ b/apps/deepl_integration/serializers.py @@ -63,6 +63,21 @@ class Status(models.IntegerChoices): status = serializers.ChoiceField(choices=Status.choices) +class ImagePathSerializer(serializers.Serializer): + page_number = serializers.IntegerField(required=True) + images = serializers.ListField( + child=serializers.CharField(allow_blank=True), + default=[] + ) + + +class TablePathSerializer(serializers.Serializer): + page_number = serializers.IntegerField(required=True) + order = serializers.IntegerField(required=True) + image_link = serializers.URLField(required=True) + content_link = serializers.URLField(required=True) + + # -- Lead class LeadExtractCallbackSerializer(DeeplServerBaseCallbackSerializer): """ @@ -70,10 +85,8 @@ class LeadExtractCallbackSerializer(DeeplServerBaseCallbackSerializer): """ url = serializers.CharField(required=False) # Data fields - images_path = serializers.ListField( - child=serializers.CharField(allow_blank=True), - required=False, default=[], - ) + images_path = serializers.ListSerializer(child=ImagePathSerializer(required=False)) + tables_path = serializers.ListSerializer(child=TablePathSerializer(required=False)) text_path = serializers.CharField(required=False, allow_null=True) total_words_count = serializers.IntegerField(required=False, default=0, allow_null=True) total_pages = serializers.IntegerField(required=False, default=0, allow_null=True) @@ -106,6 +119,7 @@ def create(self, data): lead, data['text_path'], data.get('images_path', [])[:10], # TODO: Support for more images, too much image will error. + data.get('tables_path', []), data.get('total_words_count'), data.get('total_pages'), data.get('text_extraction_id'), diff --git a/apps/entry/serializers.py b/apps/entry/serializers.py index 8bef07f866..1340b53897 100644 --- a/apps/entry/serializers.py +++ b/apps/entry/serializers.py @@ -17,7 +17,7 @@ from gallery.serializers import FileSerializer, SimpleFileSerializer from project.models import Project from lead.serializers import LeadSerializer -from lead.models import Lead, LeadPreviewImage +from lead.models import Lead, LeadPreviewAttachment from analysis_framework.serializers import AnalysisFrameworkSerializer from geo.models import GeoArea, Region from geo.serializers import SimpleRegionSerializer @@ -211,7 +211,7 @@ class EntrySerializer(RemoveNullFieldsMixin, lead_image = serializers.PrimaryKeyRelatedField( required=False, write_only=True, - queryset=LeadPreviewImage.objects.all() + queryset=LeadPreviewAttachment.objects.all() ) # NOTE: Provided by annotate `annotate_comment_count` verified_by_count = serializers.IntegerField(read_only=True) @@ -594,7 +594,7 @@ class EntryGqSerializer(ProjectPropertySerializerMixin, TempClientIdMixin, UserR lead_image = serializers.PrimaryKeyRelatedField( required=False, write_only=True, - queryset=LeadPreviewImage.objects.all(), + queryset=LeadPreviewAttachment.objects.all(), help_text=( 'This is used to add images from Lead Preview Images.' ' This will be changed into gallery image and supplied back in image field.' diff --git a/apps/entry/tests/test_apis.py b/apps/entry/tests/test_apis.py index a090be0f69..be3b591caf 100644 --- a/apps/entry/tests/test_apis.py +++ b/apps/entry/tests/test_apis.py @@ -5,7 +5,7 @@ from deep.tests import TestCase from project.models import Project from user.models import User -from lead.models import Lead, LeadPreviewImage +from lead.models import Lead, LeadPreviewAttachment from organization.models import Organization, OrganizationType from analysis_framework.models import ( AnalysisFramework, Widget, Filter @@ -724,7 +724,7 @@ def test_entry_image_validation(self): self.authenticate() # Using lead image (same lead) - data['lead_image'] = self.create(LeadPreviewImage, lead=lead, file=image.file).pk + data['lead_image'] = self.create(LeadPreviewAttachment, lead=lead, file=image.file).pk response = self.client.post(url, data) self.assert_201(response) assert 'image' in response.data @@ -732,7 +732,7 @@ def test_entry_image_validation(self): data.pop('lead_image') # Using lead image (different lead) - data['lead_image'] = self.create(LeadPreviewImage, lead=self.create_lead(), file=image.file).pk + data['lead_image'] = self.create(LeadPreviewAttachment, lead=self.create_lead(), file=image.file).pk response = self.client.post(url, data) self.assert_400(response) data.pop('lead_image') diff --git a/apps/lead/admin.py b/apps/lead/admin.py index 0052268ff3..ef6249ce34 100644 --- a/apps/lead/admin.py +++ b/apps/lead/admin.py @@ -7,7 +7,7 @@ from .tasks import extract_from_lead from .models import ( Lead, LeadGroup, - LeadPreview, LeadPreviewImage, + LeadPreview, LeadPreviewAttachment, EMMEntity, ) @@ -16,8 +16,8 @@ class LeadPreviewInline(admin.StackedInline): model = LeadPreview -class LeadPreviewImageInline(admin.TabularInline): - model = LeadPreviewImage +class LeadPreviewAttachmentInline(admin.TabularInline): + model = LeadPreviewAttachment extra = 0 @@ -42,7 +42,7 @@ def trigger_lead_extract(modeladmin, request, queryset): @admin.register(Lead) class LeadAdmin(VersionAdmin): - inlines = [LeadPreviewInline, LeadPreviewImageInline] + inlines = [LeadPreviewInline, LeadPreviewAttachmentInline] search_fields = ['title'] list_filter = ( AutocompleteFilterFactory('Project', 'project'), diff --git a/apps/lead/dataloaders.py b/apps/lead/dataloaders.py index 91a6e43c8f..3695171020 100644 --- a/apps/lead/dataloaders.py +++ b/apps/lead/dataloaders.py @@ -11,7 +11,7 @@ from organization.dataloaders import OrganizationLoader -from .models import Lead, LeadPreview, LeadGroup +from .models import Lead, LeadPreview, LeadGroup, LeadPreviewAttachment from assisted_tagging.models import DraftEntry from assessment_registry.models import AssessmentRegistry @@ -26,6 +26,15 @@ def batch_load_fn(self, keys): return Promise.resolve([_map.get(key) for key in keys]) +class LeadPreviewAttachmentLoader(DataLoaderWithContext): + def batch_load_fn(self, keys): + lead_preview_attachment_qs = LeadPreviewAttachment.objects.filter(lead__in=keys) + lead_preview_attachments = defaultdict(list) + for lead_preview_attachment in lead_preview_attachment_qs: + lead_preview_attachments[lead_preview_attachment.lead_id].append(lead_preview_attachment) + return Promise.resolve([lead_preview_attachments.get(key) for key in keys]) + + class EntriesCountLoader(DataLoaderWithContext): def batch_load_fn(self, keys): active_af = self.context.active_project.analysis_framework @@ -137,6 +146,10 @@ class DataLoaders(WithContextMixin): def lead_preview(self): return LeadPreviewLoader(context=self.context) + @cached_property + def lead_preview_attachment(self): + return LeadPreviewAttachmentLoader(context=self.context) + @cached_property def entries_count(self): return EntriesCountLoader(context=self.context) diff --git a/apps/lead/enums.py b/apps/lead/enums.py index a767fe58de..39516159ed 100644 --- a/apps/lead/enums.py +++ b/apps/lead/enums.py @@ -16,6 +16,7 @@ Lead.AutoExtractionStatus, name='LeadAutoEntryExtractionTypeEnum' ) + enum_map = { get_enum_name_from_django_field(field): enum for field, enum in ( diff --git a/apps/lead/factories.py b/apps/lead/factories.py index 167974f145..2f60d667d8 100644 --- a/apps/lead/factories.py +++ b/apps/lead/factories.py @@ -11,7 +11,7 @@ LeadGroup, LeadEMMTrigger, LeadPreview, - LeadPreviewImage, + LeadPreviewAttachment, UserSavedLeadFilter, ) @@ -84,9 +84,9 @@ class Meta: model = LeadPreview -class LeadPreviewImageFactory(DjangoModelFactory): +class LeadPreviewAttachmentFactory(DjangoModelFactory): class Meta: - model = LeadPreviewImage + model = LeadPreviewAttachment class UserSavedLeadFilterFactory(DjangoModelFactory): diff --git a/apps/lead/migrations/0050_auto_20240606_0608.py b/apps/lead/migrations/0050_auto_20240606_0608.py new file mode 100644 index 0000000000..bf17c0883c --- /dev/null +++ b/apps/lead/migrations/0050_auto_20240606_0608.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.25 on 2024-06-06 06:08 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('lead', '0049_auto_20231121_0926_squashed_0054_auto_20231218_0552'), + ] + + operations = [ + migrations.CreateModel( + name='LeadPreviewAttachment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('order', models.IntegerField(default=0)), + ('page_number', models.IntegerField(default=0)), + ('type', models.CharField(choices=[('XLSX', 'XLSX'), ('image', 'Image')], max_length=20)), + ('file', models.FileField(upload_to='lead-preview/attachments/')), + ('file_preview', models.FileField(upload_to='lead-preview/attachments-preview/')), + ('lead', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='lead.lead')), + ], + ), + migrations.DeleteModel( + name='LeadPreviewImage', + ), + ] diff --git a/apps/lead/models.py b/apps/lead/models.py index eb04b1fe5a..98403aa87f 100644 --- a/apps/lead/models.py +++ b/apps/lead/models.py @@ -372,14 +372,25 @@ def __str__(self): return 'Text extracted for {}'.format(self.lead) -class LeadPreviewImage(models.Model): +class LeadPreviewAttachment(models.Model): """ NOTE: File can be only used by gallery (when attached to a entry) """ + class AttachementFileType(models.TextChoices): + XLSX = 'XLSX', 'XLSX' + IMAGE = 'image', 'Image' + lead = models.ForeignKey( Lead, related_name='images', on_delete=models.CASCADE, ) - file = models.FileField(upload_to='lead-preview/') + order = models.IntegerField(default=0) + page_number = models.IntegerField(default=0) + type = models.CharField( + max_length=20, + choices=AttachementFileType.choices, + ) + file = models.FileField(upload_to='lead-preview/attachments/') + file_preview = models.FileField(upload_to='lead-preview/attachments-preview/') def __str__(self): return 'Image extracted for {}'.format(self.lead) diff --git a/apps/lead/schema.py b/apps/lead/schema.py index cf352b7031..519aee5b13 100644 --- a/apps/lead/schema.py +++ b/apps/lead/schema.py @@ -8,7 +8,7 @@ from utils.graphene.pagination import NoOrderingPageGraphqlPagination from utils.graphene.enums import EnumDescription -from utils.graphene.types import CustomDjangoListObjectType, ClientIdMixin +from utils.graphene.types import CustomDjangoListObjectType, ClientIdMixin, FileFieldType from utils.graphene.fields import DjangoPaginatedListObjectField from user.models import User @@ -33,6 +33,7 @@ LeadEMMTrigger, EMMEntity, UserSavedLeadFilter, + LeadPreviewAttachment, ) from .enums import ( LeadConfidentialityEnum, @@ -216,6 +217,21 @@ class Meta: ) +class LeadPreviewAttachmentsType(DjangoObjectType): + file = graphene.Field(FileFieldType) + file_preview = graphene.Field(FileFieldType) + + class Meta: + model = LeadPreviewAttachment + only_fields = ( + 'type', + 'page_number', + 'order', + 'file', + 'file_preview', + ) + + class LeadEmmTriggerType(DjangoObjectType): class Meta: model = LeadEMMTrigger @@ -347,6 +363,7 @@ class Meta: extraction_status = graphene.Field(LeadExtractionStatusEnum) lead_preview = graphene.Field(LeadPreviewType) + lead_preview_attachments = graphene.List(graphene.NonNull(LeadPreviewAttachmentsType)) source = graphene.Field(OrganizationType) authors = DjangoListField(OrganizationType) assignee = graphene.Field(UserType) @@ -412,6 +429,9 @@ def resolve_attachment(root, info, **kwargs): if root.attachment_id: return info.context.dl.deep_gallery.file.load(root.attachment_id) + def resolve_lead_preview_attachments(root, info, **kwargs): + return info.context.dl.lead.lead_preview_attachment.load(root.pk) + class DraftEntryCountByLead(graphene.ObjectType): undiscarded_draft_entry = graphene.Int(required=False) diff --git a/apps/lead/serializers.py b/apps/lead/serializers.py index f8879ae09e..0267122691 100644 --- a/apps/lead/serializers.py +++ b/apps/lead/serializers.py @@ -37,7 +37,7 @@ Lead, LeadEMMTrigger, LeadGroup, - LeadPreviewImage, + LeadPreviewAttachment, UserSavedLeadFilter, ) @@ -288,9 +288,11 @@ def update(self, instance, validated_data): return lead -class LeadPreviewImageSerializer(RemoveNullFieldsMixin, - DynamicFieldsMixin, - serializers.ModelSerializer): +class LeadPreviewAttachmentSerializer( + RemoveNullFieldsMixin, + DynamicFieldsMixin, + serializers.ModelSerializer +): """ Serializer for lead preview image """ @@ -298,7 +300,7 @@ class LeadPreviewImageSerializer(RemoveNullFieldsMixin, file = URLCachedFileField(read_only=True) class Meta: - model = LeadPreviewImage + model = LeadPreviewAttachment fields = ('id', 'file',) @@ -310,7 +312,7 @@ class LeadPreviewSerializer(RemoveNullFieldsMixin, text = serializers.CharField(source='leadpreview.text_extract', read_only=True) - images = LeadPreviewImageSerializer(many=True, read_only=True) + images = LeadPreviewAttachmentSerializer(many=True, read_only=True) classified_doc_id = serializers.IntegerField( source='leadpreview.classified_doc_id', read_only=True, @@ -634,7 +636,7 @@ def _get_clone_ready(obj, lead): new_lead.authors.set(authors) # Clone Many to one Fields - LeadPreviewImage.objects.bulk_create([ + LeadPreviewAttachment.objects.bulk_create([ _get_clone_ready(image, new_lead) for image in preview_images ]) LeadEMMTrigger.objects.bulk_create([ diff --git a/apps/lead/tests/test_apis.py b/apps/lead/tests/test_apis.py index 681e717ca0..5a813e2537 100644 --- a/apps/lead/tests/test_apis.py +++ b/apps/lead/tests/test_apis.py @@ -37,7 +37,7 @@ from lead.models import ( Lead, LeadPreview, - LeadPreviewImage, + LeadPreviewAttachment, EMMEntity, LeadEMMTrigger, LeadGroup, @@ -811,7 +811,7 @@ def test_lead_copy(self): # Generating Foreign elements for lead1 self.create(LeadPreview, lead=lead1, text_extract=lead1_text_extract) - self.create(LeadPreviewImage, lead=lead1, file=lead1_preview_file) + self.create(LeadPreviewAttachment, lead=lead1, file=lead1_preview_file) emm_trigger = self.create( LeadEMMTrigger, lead=lead1, emm_keyword=emm_keyword, emm_risk_factor=emm_risk_factor, count=emm_count) lead1.emm_entities.set([self.create(EMMEntity, name=emm_entity_name)]) @@ -1797,7 +1797,16 @@ def test_extractor_callback_url(self, get_file_mock, get_text_mock, index_lead_f data = { 'client_id': LeadExtractionHandler.get_client_id(self.lead), - 'images_path': ['http://random.com/image1.jpeg', 'http://random.com/image1.jpeg'], + 'images_path': [ + { + 'page_number': 1, + 'images': [ + 'http://random.com/image1.jpeg', + 'http://random.com/image1.jpeg' + ], + } + ], + 'tables_path': [], 'text_path': 'http://random.com/extracted_file.txt', 'url': 'http://random.com/pdf_file.pdf', 'total_words_count': 300, @@ -1812,7 +1821,7 @@ def test_extractor_callback_url(self, get_file_mock, get_text_mock, index_lead_f self.lead.refresh_from_db() self.assertEqual(self.lead.extraction_status, Lead.ExtractionStatus.FAILED) self.assertEqual(LeadPreview.objects.filter(lead=self.lead).count(), 0) - self.assertEqual(LeadPreviewImage.objects.filter(lead=self.lead).count(), 0) + self.assertEqual(LeadPreviewAttachment.objects.filter(lead=self.lead).count(), 0) data['status'] = DeeplServerBaseCallbackSerializer.Status.SUCCESS.value # After callback [Success] @@ -1826,7 +1835,7 @@ def test_extractor_callback_url(self, get_file_mock, get_text_mock, index_lead_f self.assertEqual(lead_preview.text_extract, 'Extracted text') self.assertEqual(lead_preview.word_count, 300) self.assertEqual(lead_preview.page_count, 4) - self.assertEqual(LeadPreviewImage.objects.filter(lead=self.lead).count(), 2) + self.assertEqual(LeadPreviewAttachment.objects.filter(lead=self.lead).count(), 2) index_lead_func.assert_called_once_with(self.lead.id) diff --git a/apps/lead/tests/test_mutations.py b/apps/lead/tests/test_mutations.py index 0a894205d5..ce85db556e 100644 --- a/apps/lead/tests/test_mutations.py +++ b/apps/lead/tests/test_mutations.py @@ -13,7 +13,7 @@ LeadGroupFactory, LeadEMMTriggerFactory, LeadPreviewFactory, - LeadPreviewImageFactory, + LeadPreviewAttachmentFactory, ) @@ -517,7 +517,7 @@ def test_lead_copy_mutation(self): # Generating Foreign elements for wa_lead1 wa_lead1_preview = LeadPreviewFactory.create(lead=wa_lead1, text_extract='This is a random text extarct') - wa_lead1_image_preview = LeadPreviewImageFactory.create(lead=wa_lead1, file='test-file-123') + wa_lead1_image_preview = LeadPreviewAttachmentFactory.create(lead=wa_lead1, file='test-file-123') LeadEMMTriggerFactory.create( lead=wa_lead1, emm_keyword='emm1', diff --git a/apps/lead/views.py b/apps/lead/views.py index b922e32770..d56e8428b8 100644 --- a/apps/lead/views.py +++ b/apps/lead/views.py @@ -48,7 +48,7 @@ Lead, EMMEntity, LeadEMMTrigger, - LeadPreviewImage, + LeadPreviewAttachment, ) from .serializers import ( raise_or_return_existing_lead, @@ -812,7 +812,7 @@ def _get_clone_ready(obj, lead): lead.authors.set(authors) # Clone Many to one Fields - LeadPreviewImage.objects.bulk_create([ + LeadPreviewAttachment.objects.bulk_create([ _get_clone_ready(image, lead) for image in preview_images ]) LeadEMMTrigger.objects.bulk_create([ diff --git a/schema.graphql b/schema.graphql index cd74429a0d..f9d55e3671 100644 --- a/schema.graphql +++ b/schema.graphql @@ -4554,6 +4554,7 @@ type LeadDetailType { statusDisplay: EnumDescription! extractionStatus: LeadExtractionStatusEnum leadPreview: LeadPreviewType + leadPreviewAttachments: [LeadPreviewAttachmentsType!] source: OrganizationType authors: [OrganizationType!] emmEntities: [EmmEntityType!] @@ -4685,6 +4686,19 @@ enum LeadOrderingEnum { DESC_ENTRIES_COUNT } +enum LeadPreviewAttachmentType { + XLSX + IMAGE +} + +type LeadPreviewAttachmentsType { + order: Int! + pageNumber: Int! + type: LeadPreviewAttachmentType! + file: FileFieldType + filePreview: FileFieldType +} + type LeadPreviewType { textExtract: String! thumbnail: String @@ -4745,6 +4759,7 @@ type LeadType { statusDisplay: EnumDescription! extractionStatus: LeadExtractionStatusEnum leadPreview: LeadPreviewType + leadPreviewAttachments: [LeadPreviewAttachmentsType!] source: OrganizationType authors: [OrganizationType!] emmEntities: [EmmEntityType!]