summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2026-03-24 17:20:43 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2026-03-25 15:10:38 +0100
commit357b31ed1526b0627e1fae90ae261a46ee28e322 (patch)
tree8a976135beffab07f1a1b0d3106c96a85b8f916c
parentbd00a0b3db9b795907d709d163f7e8217f7c7671 (diff)
downloadIshtar-357b31ed1526b0627e1fae90ae261a46ee28e322.tar.bz2
Ishtar-357b31ed1526b0627e1fae90ae261a46ee28e322.zip
✨ qualified biographical note/site actors - autocomplete forms and actor form
-rw-r--r--archaeological_operations/forms.py22
-rw-r--r--ishtar_common/forms_common.py62
-rw-r--r--ishtar_common/urls.py8
-rw-r--r--ishtar_common/views.py34
4 files changed, 112 insertions, 14 deletions
diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py
index ba59f4419..f25d9f2cc 100644
--- a/archaeological_operations/forms.py
+++ b/archaeological_operations/forms.py
@@ -31,7 +31,6 @@ from django.core import validators
from django.db.models import Max
from django.forms.formsets import formset_factory, DELETION_FIELD_NAME, \
TOTAL_FORM_COUNT
-from django.utils.functional import lazy
from django.utils.safestring import mark_safe
from ishtar_common.utils import gettext_lazy as _, pgettext_lazy, parse_parcels
@@ -46,9 +45,7 @@ from ishtar_common.forms import FinalForm, FormSet, \
from ishtar_common.forms_common import TownFormSet, get_town_field, TownForm
from ishtar_common.models import valid_id, valid_ids, Person, Town, \
DocumentTemplate, Organization, get_current_profile, \
- person_type_pks_lazy, person_type_pk_lazy, organization_type_pks_lazy, \
- organization_type_pk_lazy, SpatialReferenceSystem, Area, \
- get_sra_agent_label, get_sra_agent_head_scientist_label, get_operator_label
+ SpatialReferenceSystem, Area, QualifiedBiographicalNote
from ishtar_common.wizards import MultiValueDict
from .widgets import ParcelWidget, SelectParcelWidget, OAWidget
@@ -1316,6 +1313,7 @@ class SiteForm(CustomForm, ManageOldType):
'spatial_reference_system': SpatialReferenceSystem,
'cultural_attribution': models.CulturalAttributionType,
'collaborator': Person,
+ "actor": QualifiedBiographicalNote,
'discoverer': Person,
"nature_of_site": models.NatureOfSiteType,
"interpretation_level": models.InterpretationLevelType,
@@ -1324,7 +1322,10 @@ class SiteForm(CustomForm, ManageOldType):
"town": Town,
"type": models.SiteType,
}
- base_models = ["period", "remain", "collaborator", "cultural_attribution", "town", "type"]
+ extra_form_modals = ["qualifiedbiographicalnote", "biographicalnote", "person",
+ "organization"]
+ base_models = ["period", "remain", "collaborator", "cultural_attribution", "town",
+ "type", "actor"]
pk = forms.IntegerField(required=False, widget=forms.HiddenInput)
reference = forms.CharField(label=_("Reference"), max_length=200)
@@ -1332,7 +1333,11 @@ class SiteForm(CustomForm, ManageOldType):
other_reference = forms.CharField(label=_("Other reference"),
required=False)
collaborator = widgets.Select2MultipleField(
- model=Person, label=_("Collaborators"), required=False, remote=True)
+ model=Person, label=_("Collaborators"), required=False,
+ remote=True, new=True)
+ actor = widgets.Select2MultipleField(
+ model=QualifiedBiographicalNote, label=_("Actors"), required=False,
+ remote=True, new=True)
description = forms.CharField(label=_("Description"), widget=forms.Textarea,
required=False)
public_description = forms.CharField(label=_("Public description"), widget=forms.Textarea,
@@ -1390,11 +1395,6 @@ class SiteForm(CustomForm, ManageOldType):
FieldType('discovery_status', models.SiteDiscoveryStatusType),
]
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- if 'collaborator' in self.fields:
- self.fields['collaborator'].widget.attrs['full-width'] = True
-
def clean_reference(self):
reference = self.cleaned_data['reference']
q = models.ArchaeologicalSite.objects.filter(reference=reference)
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index c782bc03d..d0b1183be 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -1522,6 +1522,68 @@ class BiographicalNoteEditForm(BiographicalNoteForm, IshtarForm):
self.fields[k].initial = value
+class QualifiedBiographicalNoteForm(ManageOldType, NewItemForm):
+ form_label = _("Actor")
+ form_admin_name = _("Actor - 010 - General")
+ form_slug = "qualifiedbiographicalnote-general"
+ extra_form_modals = ["biographical_note"]
+ associated_models = {
+ "biographical_note": models.BiographicalNote,
+ "qualification_type": models.QualifiedBiographicalNoteType
+ }
+ biographical_note = forms.IntegerField(
+ label=_("Biographical note"),
+ widget=widgets.JQueryAutoComplete(
+ reverse_lazy("autocomplete-biographicalnote"),
+ associated_model=models.BiographicalNote,
+ new=True,
+ ),
+ validators=[models.valid_id(models.BiographicalNote)],
+ required=True,
+ )
+ qualification_type = forms.ChoiceField(label=_("Qualification type"), choices=[],
+ required=True)
+ TYPES = [
+ FieldType("qualification_type", models.QualifiedBiographicalNoteType),
+ ]
+
+ def save(self, user, item=None):
+ dct = self.cleaned_data
+ dct["history_modifier"] = user
+ for key in self.associated_models.keys():
+ if key in dct:
+ if not dct[key]:
+ dct.pop(key)
+ else:
+ model = self.associated_models[key]
+ try:
+ dct[key] = model.objects.get(pk=dct[key])
+ except model.DoesNotExist:
+ dct.pop(key)
+ # get data
+ data = {}
+ for k in list(dct.keys()):
+ if k.startswith("data__"):
+ v = dct.pop(k)
+ keys = k.split("__")[1:]
+ dct = generate_dict_from_list(keys, v)
+ data = update_data(data, dct)
+
+ if not item:
+ item = models.QualifiedBiographicalNote.objects.create(**dct)
+ else:
+ for k in dct:
+ setattr(item, k, dct[k])
+ item.save()
+
+ # set data
+ if item.data or data:
+ data = update_data(item.data, data)
+ item.data = data
+ item.save()
+ return item
+
+
class AccountForm(IshtarForm):
form_label = _("Account")
associated_models = {"pk": models.Person}
diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py
index 3d91d7493..78b185ac7 100644
--- a/ishtar_common/urls.py
+++ b/ishtar_common/urls.py
@@ -527,6 +527,11 @@ urlpatterns += [
name="new-biographicalnote",
),
re_path(
+ r"new-qualifiedbiographicalnote/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$",
+ views.new_qualifiedbiographicalnote,
+ name="new-qualifiedbiographicalnote",
+ ),
+ re_path(
r"^biographicalnote-qa-edit/(?P<pks>[0-9-]+)?/$",
check_permissions(
["ishtar_common.change_biographicalnote",
@@ -610,6 +615,9 @@ urlpatterns += [
views.autocomplete_biographical_note,
name="autocomplete-biographicalnote"
),
+ re_path(r"autocomplete-qualifiedbiographicalnote/$",
+ views.autocomplete_qualified_biographical_note,
+ name="autocomplete-qualifiedbiographicalnote"),
re_path(r"changelog/(?:(?P<page>\d+)/)?", views.ChangelogView.as_view(), name="changelog"),
re_path(r"person-merge/(?:(?P<page>\d+)/)?$", views.person_merge, name="person_merge"),
re_path(
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index 545c4a413..4e8376dfc 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -1171,7 +1171,7 @@ def autocomplete_author(request):
def autocomplete_biographical_note(request):
- query = get_autocomplete_query(request, "ishtar_common", "person")
+ query = get_autocomplete_query(request, "ishtar_common", "BiographicalNote")
if query is None:
return HttpResponse("[]", content_type="text/plain")
q = request.GET.get("term", "")
@@ -1187,8 +1187,31 @@ def autocomplete_biographical_note(request):
| Q(denomination__unaccent__icontains=q)
)
query = query & qu
- users = models.BiographicalNote.objects.filter(query).distinct()[:limit]
- data = json.dumps([{"id": user.pk, "value": str(user)} for user in users])
+ items = models.BiographicalNote.objects.filter(query).distinct()[:limit]
+ data = json.dumps([{"id": item.pk, "value": str(item)} for item in items])
+ return HttpResponse(data, content_type="text/plain")
+
+
+def autocomplete_qualified_biographical_note(request):
+ query = get_autocomplete_query(request, "ishtar_common", "QualifiedBiographicalNote")
+ if query is None:
+ return HttpResponse("[]", content_type="text/plain")
+ q = request.GET.get("term", "")
+ limit = request.GET.get("limit", 20)
+ try:
+ limit = int(limit)
+ except ValueError:
+ return HttpResponseBadRequest()
+ for q in q.split(" "):
+ qu = (
+ Q(biographical_note__last_name__unaccent__icontains=q)
+ | Q(biographical_note__first_name__unaccent__icontains=q)
+ | Q(biographical_note__denomination__unaccent__icontains=q)
+ | Q(qualification_type__label__unaccent__icontains=q)
+ )
+ query = query & qu
+ items = models.QualifiedBiographicalNote.objects.filter(query).distinct()[:limit]
+ data = json.dumps([{"id": item.pk, "value": str(item)} for item in items])
return HttpResponse(data, content_type="text/plain")
@@ -1220,6 +1243,11 @@ new_biographical_note = new_qa_item(
models.BiographicalNote, forms.BiographicalNoteForm, page_name=_("New biographical note")
)
+new_qualifiedbiographicalnote = new_qa_item(
+ models.QualifiedBiographicalNote, forms.QualifiedBiographicalNoteForm,
+ page_name=_("New actor")
+)
+
get_person_for_account = get_item(
models.Person,
"get_person",