From 9fd9b38849b0101fd4fa0c105c59eb2837179f20 Mon Sep 17 00:00:00 2001 From: Gytha Ogg Date: Tue, 23 Apr 2024 08:02:17 +0200 Subject: [PATCH 1/7] precommit isort --- apis_ontology/tables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apis_ontology/tables.py b/apis_ontology/tables.py index 401f494..3d02381 100644 --- a/apis_ontology/tables.py +++ b/apis_ontology/tables.py @@ -2,7 +2,7 @@ from apis_core.apis_entities.tables import AbstractEntityTable from django_tables2.utils import A -from .templatetags.linkify_list import render_links, render_list_field +from .templatetags.linkify_list import render_links from .models import Instance, Person, Place, Work From 507c7af37e11e16edc0273fccfab68b180837054 Mon Sep 17 00:00:00 2001 From: Gytha Ogg Date: Tue, 23 Apr 2024 08:02:34 +0200 Subject: [PATCH 2/7] Create an endswith customfilter --- apis_ontology/templatetags/filter_utils.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 apis_ontology/templatetags/filter_utils.py diff --git a/apis_ontology/templatetags/filter_utils.py b/apis_ontology/templatetags/filter_utils.py new file mode 100644 index 0000000..0230cf8 --- /dev/null +++ b/apis_ontology/templatetags/filter_utils.py @@ -0,0 +1,9 @@ +from django import template + +register = template.Library() + + +@register.filter +def endswith(value, suffix): + """Custom filter to check if value ends with the specified suffix.""" + return str(value).endswith(suffix) From ffd8795cb14887736749ea6f2b0423ef109fd8ab Mon Sep 17 00:00:00 2001 From: Gytha Ogg Date: Tue, 23 Apr 2024 08:54:59 +0200 Subject: [PATCH 3/7] Parse comment in 3 steps --- .../generic/partials/object_table.html | 23 ++++++++++++ apis_ontology/templatetags/parse_comment.py | 37 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 apis_ontology/templates/generic/partials/object_table.html create mode 100644 apis_ontology/templatetags/parse_comment.py diff --git a/apis_ontology/templates/generic/partials/object_table.html b/apis_ontology/templates/generic/partials/object_table.html new file mode 100644 index 0000000..8bc8a1a --- /dev/null +++ b/apis_ontology/templates/generic/partials/object_table.html @@ -0,0 +1,23 @@ +{% load apisgeneric %} +{% load filter_utils %} +{% load parse_comment %} + + + {% modeldict object as d %} + {% for key, value in d.items %} + + + + + + + {% endfor %} +
+ {{ key.verbose_name | title}} + + {% if key|endswith:'.comments' %} + {{ value | parse_comment | safe}} + {% else %} + {{ value }} + {% endif %} +
diff --git a/apis_ontology/templatetags/parse_comment.py b/apis_ontology/templatetags/parse_comment.py new file mode 100644 index 0000000..7ae61bc --- /dev/null +++ b/apis_ontology/templatetags/parse_comment.py @@ -0,0 +1,37 @@ +import re + +from django import template + +register = template.Library() + + +@register.filter +def parse_comment(value): + if not value: + return "" + print(f"Parsing {value}") + + if "<<" in value and ">>" in value: + # When comment contains a text to link and a Zotero ID in square bracckets + pattern = r"<<(.*?) \[(.*?)\]>>" + subbed = re.sub( + pattern, + r'\1', + value, + ) + value = subbed + + if "[" in value and "]" in value: + # Only Zotero ID without hyperlink text in square brackets + pattern = r"\[([A-Z0-9]+)\]" + replacement = r'\1' + subbed = re.sub(pattern, replacement, value) + value = subbed + + if "(ID:" in value: + pattern = r"\(ID:\s*(\d+)\)" + replacement = r'\1' + subbed = re.sub(pattern, replacement, value) + value = subbed + + return value From 31302639baa5cbd2a150c632281d3d412f930a6f Mon Sep 17 00:00:00 2001 From: Gytha Ogg Date: Tue, 23 Apr 2024 09:02:14 +0200 Subject: [PATCH 4/7] Single reg ex instead of 3 --- apis_ontology/templatetags/parse_comment.py | 50 +++++++++++---------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/apis_ontology/templatetags/parse_comment.py b/apis_ontology/templatetags/parse_comment.py index 7ae61bc..35f5288 100644 --- a/apis_ontology/templatetags/parse_comment.py +++ b/apis_ontology/templatetags/parse_comment.py @@ -11,27 +11,29 @@ def parse_comment(value): return "" print(f"Parsing {value}") - if "<<" in value and ">>" in value: - # When comment contains a text to link and a Zotero ID in square bracckets - pattern = r"<<(.*?) \[(.*?)\]>>" - subbed = re.sub( - pattern, - r'\1', - value, - ) - value = subbed - - if "[" in value and "]" in value: - # Only Zotero ID without hyperlink text in square brackets - pattern = r"\[([A-Z0-9]+)\]" - replacement = r'\1' - subbed = re.sub(pattern, replacement, value) - value = subbed - - if "(ID:" in value: - pattern = r"\(ID:\s*(\d+)\)" - replacement = r'\1' - subbed = re.sub(pattern, replacement, value) - value = subbed - - return value + def replace_zotero_link(match): + if match.group("text"): + # Case: <> + text = match.group("text") + zotero_id = match.group("zotero_id") + return f'{text}' + elif match.group("zotero_id_only"): + # Case: [ID] + zotero_id = match.group("zotero_id_only") + return f'{zotero_id}' + + def replace_entity_link(match): + entity_id = match.group("entity_id") + return f'{entity_id}' + + # Combined regex pattern to handle all cases + combined_pattern = r"<<(?P.*?) \[(?P[A-Z0-9]+)\]>>|\[(?P[A-Z0-9]+)\]|\(ID:\s*(?P\d+)\)" + + # Apply substitutions using the combined pattern + transformed_value = re.sub( + combined_pattern, + lambda match: replace_zotero_link(match) or replace_entity_link(match), + value, + ) + + return transformed_value From 9ca93dfa53ab8e1265b8afe79e93b7ce6d5019f2 Mon Sep 17 00:00:00 2001 From: Gytha Ogg Date: Tue, 23 Apr 2024 09:21:44 +0200 Subject: [PATCH 5/7] Show Zotero short title wherever available --- apis_ontology/templatetags/parse_comment.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apis_ontology/templatetags/parse_comment.py b/apis_ontology/templatetags/parse_comment.py index 35f5288..375b385 100644 --- a/apis_ontology/templatetags/parse_comment.py +++ b/apis_ontology/templatetags/parse_comment.py @@ -1,7 +1,12 @@ import re +import logging + +logger = logging.getLogger(__name__) from django import template +from apis_ontology.models import ZoteroEntry + register = template.Library() @@ -20,7 +25,12 @@ def replace_zotero_link(match): elif match.group("zotero_id_only"): # Case: [ID] zotero_id = match.group("zotero_id_only") - return f'{zotero_id}' + try: + zotero_obj = ZoteroEntry.objects.filter(zoteroId=zotero_id)[0] + return f'{zotero_obj.shortTitle}' + except Exception as e: + logger.error(e) + return f'{zotero_id}' def replace_entity_link(match): entity_id = match.group("entity_id") From d30cbe76597b2b7fc36092b2c541fb178db69353 Mon Sep 17 00:00:00 2001 From: Gytha Ogg Date: Tue, 23 Apr 2024 10:31:00 +0200 Subject: [PATCH 6/7] Return label/name with primary key for entities --- apis_ontology/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apis_ontology/models.py b/apis_ontology/models.py index 0ffff6f..6eba277 100644 --- a/apis_ontology/models.py +++ b/apis_ontology/models.py @@ -77,7 +77,7 @@ class Meta: verbose_name_plural = _("Persons") def __str__(self): - return f"{self.name}" + return f"{self.name} ({self.pk})" class Place( @@ -138,7 +138,7 @@ class Meta: verbose_name_plural = _("Works") def __str__(self): - return f"{self.name}" + return f"{self.name} ({self.pk})" class Instance( @@ -228,7 +228,7 @@ class Meta: verbose_name_plural = _("Instances") def __str__(self): - return f"{self.name}" + return f"{self.name} ({self.pk})" class ZoteroEntry(GenericModel, models.Model): From dfa5cdcf83fcc20119468fc1c7e2d03300cdf558 Mon Sep 17 00:00:00 2001 From: Gytha Ogg Date: Tue, 23 Apr 2024 10:32:33 +0200 Subject: [PATCH 7/7] Use a single custom_replace method This handles - [ZoteroID] - (ID:pk) - <> --- apis_ontology/templatetags/parse_comment.py | 51 +++++++++++++-------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/apis_ontology/templatetags/parse_comment.py b/apis_ontology/templatetags/parse_comment.py index 375b385..347c241 100644 --- a/apis_ontology/templatetags/parse_comment.py +++ b/apis_ontology/templatetags/parse_comment.py @@ -4,46 +4,57 @@ logger = logging.getLogger(__name__) from django import template +from django.contrib.contenttypes.models import ContentType from apis_ontology.models import ZoteroEntry +from apis_core.apis_metainfo.models import RootObject register = template.Library() @register.filter def parse_comment(value): - if not value: - return "" - print(f"Parsing {value}") - - def replace_zotero_link(match): + def custom_replace(match): if match.group("text"): - # Case: <> + # Handle <> text = match.group("text") zotero_id = match.group("zotero_id") - return f'{text}' + replacement = f'{text}' elif match.group("zotero_id_only"): - # Case: [ID] + # Handle [ZoteroID] zotero_id = match.group("zotero_id_only") try: zotero_obj = ZoteroEntry.objects.filter(zoteroId=zotero_id)[0] - return f'{zotero_obj.shortTitle}' + link_text = ( + zotero_obj.shortTitle if zotero_obj.shortTitle else zotero_id + ) + return f'{link_text}' except Exception as e: - logger.error(e) + logger.error(f"Error finding cached Zotero entry with ID %s", zotero_id) + logger.error(repr(e)) return f'{zotero_id}' + elif match.group("entity_id"): + # Handle (ID: number) + entity_id = match.group("entity_id") + try: + root_obj = RootObject.objects_inheritance.get_subclass(pk=entity_id) + ct = ContentType.objects.get_for_model(root_obj) + return f'{root_obj}' + + except Exception as e: + logger.error("Error finding entity #%s", entity_id) + logger.error(repr(e)) + return f'{entity_id}' + else: + # If no specific group is matched, return the original match + replacement = match.group(0) - def replace_entity_link(match): - entity_id = match.group("entity_id") - return f'{entity_id}' + return replacement - # Combined regex pattern to handle all cases + # Define the regex pattern to capture different groups combined_pattern = r"<<(?P.*?) \[(?P[A-Z0-9]+)\]>>|\[(?P[A-Z0-9]+)\]|\(ID:\s*(?P\d+)\)" - # Apply substitutions using the combined pattern - transformed_value = re.sub( - combined_pattern, - lambda match: replace_zotero_link(match) or replace_entity_link(match), - value, - ) + # Apply substitutions using the combined pattern and custom replacement function + transformed_value = re.sub(combined_pattern, custom_replace, value) return transformed_value