diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2023-04-18 17:21:38 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2023-04-18 17:21:38 +0200 |
commit | a589b3ef96c9adf4e408713201ffe7d269e4f78f (patch) | |
tree | 5ad635c7fba5f5d1d1a40a5c5066321c870edfac /ishtar_common/models_common.py | |
parent | 2b9862d29073e31cc89e807fd355a691b0d932dd (diff) | |
download | Ishtar-a589b3ef96c9adf4e408713201ffe7d269e4f78f.tar.bz2 Ishtar-a589b3ef96c9adf4e408713201ffe7d269e4f78f.zip |
Document -> Town/Area: models, admin, forms
Diffstat (limited to 'ishtar_common/models_common.py')
-rw-r--r-- | ishtar_common/models_common.py | 359 |
1 files changed, 189 insertions, 170 deletions
diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py index 1e6da2b7d..8942d57c2 100644 --- a/ishtar_common/models_common.py +++ b/ishtar_common/models_common.py @@ -1978,6 +1978,175 @@ class OwnPerms(object): return q +class DocumentItem: + ALT_NAMES = { + "documents__image__isnull": SearchAltName( + pgettext_lazy("key for text search", "has-image"), + "documents__image__isnull", + ), + "documents__associated_url__isnull": SearchAltName( + pgettext_lazy("key for text search", "has-url"), + "documents__associated_url__isnull", + ), + "documents__associated_file__isnull": SearchAltName( + pgettext_lazy("key for text search", "has-attached-file"), + "documents__associated_file__isnull", + ), + } + + def documents_list(self) -> list: + Document = apps.get_model("ishtar_common", "Document") + return self.get_associated_main_item_list("documents", Document) + + def public_representation(self): + images = [] + if getattr(self, "main_image", None): + images.append(self.main_image.public_representation()) + images += [ + image.public_representation() + for image in self.images_without_main_image.all() + ] + return {"images": images} + + @property + def images(self): + if not hasattr(self, "documents"): + Document = apps.get_model("ishtar_common", "Document") + return Document.objects.none() + return ( + self.documents.filter(image__isnull=False).exclude(image="").order_by("pk") + ) + + @property + def images_number(self): + return self.images.count() + + @property + def images_without_main_image(self): + if not hasattr(self, "main_image") or not hasattr(self, "documents"): + return self.images + if not self.main_image: + return ( + self.documents.filter(image__isnull=False) + .exclude(image="") + .order_by("pk") + ) + return ( + self.documents.filter(image__isnull=False) + .exclude(image="") + .exclude(pk=self.main_image.pk) + .order_by("pk") + ) + + @property + def pdf_attached(self): + for document in self.documents.filter( + Q(associated_file__isnull=False) | Q(source__associated_file__isnull=False) + ).all(): + return document.pdf_attached + + def get_extra_actions(self, request): + """ + For sheet template: return "Add document / image" action + """ + # url, base_text, icon, extra_text, extra css class, is a quick action + try: + actions = super(DocumentItem, self).get_extra_actions(request) + except AttributeError: + actions = [] + + if not hasattr(self, "SLUG"): + return actions + + can_add_doc = self.can_do(request, "add_document") + if can_add_doc and ( + not hasattr(self, "is_locked") or not self.is_locked(request.user) + ): + actions += [ + ( + reverse("create-document") + "?{}={}".format(self.SLUG, self.pk), + _("Add document/image"), + "fa fa-plus", + _("doc./image"), + "", + False, + ) + ] + return actions + + +def clean_duplicate_association(document, related_item, action): + profile = get_current_profile() + if not profile.clean_redundant_document_association or action != "post_add": + return + class_name = related_item.__class__.__name__ + if class_name not in ("Find", "ContextRecord", "Operation"): + return + if class_name == "Find": + for cr in document.context_records.filter( + base_finds__find__pk=related_item.pk + ).all(): + document.context_records.remove(cr) + for ope in document.operations.filter( + context_record__base_finds__find__pk=related_item.pk + ).all(): + document.operations.remove(ope) + return + if class_name == "ContextRecord": + for ope in document.operations.filter(context_record__pk=related_item.pk).all(): + document.operations.remove(ope) + if document.finds.filter(base_finds__context_record=related_item.pk).count(): + document.context_records.remove(related_item) + return + if class_name == "Operation": + if document.context_records.filter(operation=related_item.pk).count(): + document.operations.remove(related_item) + return + if document.finds.filter( + base_finds__context_record__operation=related_item.pk + ).count(): + document.operations.remove(related_item) + return + + +def document_attached_changed(sender, **kwargs): + # associate a default main image + instance = kwargs.get("instance", None) + model = kwargs.get("model", None) + pk_set = kwargs.get("pk_set", None) + if not instance or not model: + return + + if hasattr(instance, "documents"): + items = [instance] + else: + if not pk_set: + return + try: + items = [model.objects.get(pk=pk) for pk in pk_set] + except model.DoesNotExist: + return + + for item in items: + clean_duplicate_association(instance, item, kwargs.get("action", None)) + for doc in item.documents.all(): + doc.regenerate_all_ids() + q = item.documents.filter(image__isnull=False).exclude(image="") + if item.main_image: + if q.filter(pk=item.main_image.pk).count(): + return + # the association has disappear not the main image anymore + item.main_image = None + item.skip_history_when_saving = True + item.save() + if not q.count(): + return + # by default get the lowest pk + item.main_image = q.order_by("pk").all()[0] + item.skip_history_when_saving = True + item.save() + + class NumberManager(models.Manager): def get_by_natural_key(self, number): return self.get(number=number) @@ -2927,7 +3096,8 @@ class TownManager(models.Manager): return self.get(numero_insee=numero_insee, year=year) -class Town(GeographicItem, Imported, models.Model): +class Town(GeographicItem, Imported, DocumentItem, models.Model): + SLUG = "town" name = models.CharField(_("Name"), max_length=100) surface = models.IntegerField(_("Surface (m2)"), blank=True, null=True) center = models.PointField( @@ -2956,6 +3126,17 @@ class Town(GeographicItem, Imported, models.Model): cached_label = models.CharField( _("Cached name"), max_length=500, null=True, blank=True, db_index=True ) + documents = models.ManyToManyField( + "Document", related_name="towns", verbose_name=_("Documents"), blank=True + ) + main_image = models.ForeignKey( + "Document", + related_name="main_image_towns", + on_delete=models.SET_NULL, + verbose_name=_("Main image"), + blank=True, + null=True, + ) objects = TownManager() class Meta: @@ -3085,6 +3266,12 @@ class Town(GeographicItem, Imported, models.Model): if self.numero_insee != old_num: return True + def _get_base_image_path(self): + if self.numero_insee and len(self.numero_insee) == 5: + prefix = self.numero_insee[:2] + return f"{self.SLUG}/{prefix}" + return self.SLUG + def _generate_cached_label(self): cached_label = self.name if settings.COUNTRY == "fr" and self.numero_insee: @@ -3112,6 +3299,7 @@ def post_save_town(sender, **kwargs): post_save.connect(post_save_town, sender=Town) m2m_changed.connect(geodata_attached_changed, sender=Town.geodata.through) +m2m_changed.connect(document_attached_changed, sender=Town.documents.through) def town_child_changed(sender, **kwargs): @@ -3563,175 +3751,6 @@ class DashboardFormItem: return q.order_by("pk").distinct("pk").count() -class DocumentItem: - ALT_NAMES = { - "documents__image__isnull": SearchAltName( - pgettext_lazy("key for text search", "has-image"), - "documents__image__isnull", - ), - "documents__associated_url__isnull": SearchAltName( - pgettext_lazy("key for text search", "has-url"), - "documents__associated_url__isnull", - ), - "documents__associated_file__isnull": SearchAltName( - pgettext_lazy("key for text search", "has-attached-file"), - "documents__associated_file__isnull", - ), - } - - def documents_list(self) -> list: - Document = apps.get_model("ishtar_common", "Document") - return self.get_associated_main_item_list("documents", Document) - - def public_representation(self): - images = [] - if getattr(self, "main_image", None): - images.append(self.main_image.public_representation()) - images += [ - image.public_representation() - for image in self.images_without_main_image.all() - ] - return {"images": images} - - @property - def images(self): - if not hasattr(self, "documents"): - Document = apps.get_model("ishtar_common", "Document") - return Document.objects.none() - return ( - self.documents.filter(image__isnull=False).exclude(image="").order_by("pk") - ) - - @property - def images_number(self): - return self.images.count() - - @property - def images_without_main_image(self): - if not hasattr(self, "main_image") or not hasattr(self, "documents"): - return self.images - if not self.main_image: - return ( - self.documents.filter(image__isnull=False) - .exclude(image="") - .order_by("pk") - ) - return ( - self.documents.filter(image__isnull=False) - .exclude(image="") - .exclude(pk=self.main_image.pk) - .order_by("pk") - ) - - @property - def pdf_attached(self): - for document in self.documents.filter( - Q(associated_file__isnull=False) | Q(source__associated_file__isnull=False) - ).all(): - return document.pdf_attached - - def get_extra_actions(self, request): - """ - For sheet template: return "Add document / image" action - """ - # url, base_text, icon, extra_text, extra css class, is a quick action - try: - actions = super(DocumentItem, self).get_extra_actions(request) - except AttributeError: - actions = [] - - if not hasattr(self, "SLUG"): - return actions - - can_add_doc = self.can_do(request, "add_document") - if can_add_doc and ( - not hasattr(self, "is_locked") or not self.is_locked(request.user) - ): - actions += [ - ( - reverse("create-document") + "?{}={}".format(self.SLUG, self.pk), - _("Add document/image"), - "fa fa-plus", - _("doc./image"), - "", - False, - ) - ] - return actions - - -def clean_duplicate_association(document, related_item, action): - profile = get_current_profile() - if not profile.clean_redundant_document_association or action != "post_add": - return - class_name = related_item.__class__.__name__ - if class_name not in ("Find", "ContextRecord", "Operation"): - return - if class_name == "Find": - for cr in document.context_records.filter( - base_finds__find__pk=related_item.pk - ).all(): - document.context_records.remove(cr) - for ope in document.operations.filter( - context_record__base_finds__find__pk=related_item.pk - ).all(): - document.operations.remove(ope) - return - if class_name == "ContextRecord": - for ope in document.operations.filter(context_record__pk=related_item.pk).all(): - document.operations.remove(ope) - if document.finds.filter(base_finds__context_record=related_item.pk).count(): - document.context_records.remove(related_item) - return - if class_name == "Operation": - if document.context_records.filter(operation=related_item.pk).count(): - document.operations.remove(related_item) - return - if document.finds.filter( - base_finds__context_record__operation=related_item.pk - ).count(): - document.operations.remove(related_item) - return - - -def document_attached_changed(sender, **kwargs): - # associate a default main image - instance = kwargs.get("instance", None) - model = kwargs.get("model", None) - pk_set = kwargs.get("pk_set", None) - if not instance or not model: - return - - if hasattr(instance, "documents"): - items = [instance] - else: - if not pk_set: - return - try: - items = [model.objects.get(pk=pk) for pk in pk_set] - except model.DoesNotExist: - return - - for item in items: - clean_duplicate_association(instance, item, kwargs.get("action", None)) - for doc in item.documents.all(): - doc.regenerate_all_ids() - q = item.documents.filter(image__isnull=False).exclude(image="") - if item.main_image: - if q.filter(pk=item.main_image.pk).count(): - return - # the association has disappear not the main image anymore - item.main_image = None - item.skip_history_when_saving = True - item.save() - if not q.count(): - return - # by default get the lowest pk - item.main_image = q.order_by("pk").all()[0] - item.skip_history_when_saving = True - item.save() - - class QuickAction: """ Quick action available from tables |