summaryrefslogtreecommitdiff
path: root/ishtar_common/forms_common.py
diff options
context:
space:
mode:
Diffstat (limited to 'ishtar_common/forms_common.py')
-rw-r--r--ishtar_common/forms_common.py204
1 files changed, 202 insertions, 2 deletions
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index 6e9e11006..695638120 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -30,6 +30,7 @@ from urllib.parse import urlparse, quote
import zipfile
from django import forms
+from django.contrib.gis import forms as gis_forms
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
@@ -71,7 +72,8 @@ from .forms import (
LockForm,
)
from ishtar_common.data_importer import ImporterError
-from ishtar_common.utils import is_downloadable, clean_session_cache, max_size_help
+from ishtar_common.utils import is_downloadable, clean_session_cache, max_size_help, \
+ reverse_coordinates
from archaeological_operations.models import Operation, OperationType
from archaeological_context_records.models import ContextRecord
@@ -1972,7 +1974,7 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
if cleaned_data.get(rel, None):
return cleaned_data
raise forms.ValidationError(
- _("A document has to be attached at least " "to one item")
+ _("A document has to be attached at least to one item")
)
def clean_publisher(self):
@@ -2562,3 +2564,201 @@ class QRSearchForm(forms.Form):
os.makedirs(dest_dir)
shutil.move(filename, dest_dir)
return os.path.join(settings.MEDIA_URL, "tmp", base_filename)
+
+
+class GISForm(forms.ModelForm, CustomForm, ManageOldType):
+ form_label = _("Geo item")
+ form_admin_name = _("Geo item - General")
+ form_slug = "geoitem-general"
+
+ extra_form_modals = []
+ associated_models = {
+ "data_type": models.GeoDataType,
+ "origin": models.GeoOriginType,
+ "provider": models.GeoProviderType,
+ }
+
+ pk = forms.IntegerField(label="", required=False, widget=forms.HiddenInput)
+ name = forms.CharField(
+ label=_("Name"),
+ required=False,
+ validators=[validators.MaxLengthValidator(500)],
+ )
+ import_key = forms.CharField(
+ label=_("Import key"),
+ required=False,
+ disabled=True,
+ help_text=_("An update via import corresponding to the source element and "
+ "this key will overwrite the data."),
+ )
+ source_content_type_id = forms.IntegerField(
+ label="", required=True, widget=forms.HiddenInput, disabled=True)
+ source_id = forms.IntegerField(
+ label="", required=True, widget=forms.HiddenInput, disabled=True)
+ data_type = widgets.ModelChoiceField(
+ model=models.GeoDataType, label=_("Data type"), choices=[], required=False
+ )
+ origin = widgets.ModelChoiceField(
+ model=models.GeoOriginType, label=_("Origin"), choices=[], required=False
+ )
+ provider = widgets.ModelChoiceField(
+ model=models.GeoProviderType, label=_("Provider"), choices=[], required=False
+ )
+ comment = forms.CharField(label=_("Comment"), widget=forms.Textarea, required=False)
+
+ TYPES = [
+ FieldType("origin", models.GeoOriginType),
+ FieldType("data_type", models.GeoDataType),
+ FieldType("provider", models.GeoProviderType),
+ ]
+
+ class Meta:
+ model = models.GeoVectorData
+ exclude = ["need_update", "imports", "cached_x", "cached_y", "cached_z",
+ "point_3d"]
+
+ HEADERS = {
+ "related_items_ishtar_common_town": FormHeader(
+ _("Related items"), collapse=True),
+ "name": FormHeader(_("Meta-data")),
+ "geo_field": FormHeader(_("Geography")),
+ }
+ OPTIONS_PERMISSIONS = [
+ # field name, permission, options
+ ("tags", ("ishtar_common.add_documenttag",), {"new": True}),
+ ]
+
+ GEO_FIELDS = (
+ ("point_2d",),
+ ("multi_points",),
+ ("multi_line",),
+ ("multi_polygon",),
+ ("x", "z")
+ )
+
+ def __init__(self, *args, **kwargs):
+ main_items_fields = {}
+ if "main_items_fields" in kwargs:
+ main_items_fields = kwargs.pop("main_items_fields")
+ self.user = None
+ if kwargs.get("user", None):
+ self.user = kwargs.pop("user")
+ instance = kwargs.get("instance", False)
+ self.is_instancied = bool(instance)
+ super(GISForm, self).__init__(*args, **kwargs)
+ if not self.fields["import_key"].initial:
+ self.fields.pop("import_key")
+ self.source_content_type = kwargs.pop("source_content_type", None)
+ self.source_id = kwargs.pop("source_id", None)
+ if not self.source_content_type:
+ self.fields.pop("source_content_type_id")
+ self.fields.pop("source_id")
+ else:
+ self.fields["source_content_type_id"].initial = self.source_content_type
+ self.fields["source_id"].initial = self.source_id
+ self.geo_keys = []
+ if instance:
+ for keys in self.GEO_FIELDS:
+ if any(getattr(instance, key) for key in keys):
+ if keys[0] != "x":
+ map_srid = getattr(instance, keys[0]).srid or 4326
+ widget = gis_forms.OSMWidget
+ if map_srid == 4326:
+ widget = widgets.ReversedOSMWidget
+ self.fields[keys[0]].widget = widget(
+ attrs={"map_srid": map_srid})
+ self.fields.pop("spatial_reference_system")
+ self.geo_keys = keys[:]
+ else:
+ self.geo_keys = [
+ "x", "estimated_error_x",
+ "y", "estimated_error_y",
+ "z", "estimated_error_z",
+ "spatial_reference_system",
+ ]
+ for geo_fields in self.GEO_FIELDS:
+ if geo_fields != keys:
+ for geo_field in geo_fields:
+ self.fields.pop(geo_field)
+ if geo_field == "x":
+ self.fields.pop("estimated_error_x")
+ self.fields.pop("y")
+ self.fields.pop("estimated_error_y")
+ if geo_field == "z":
+ self.fields.pop("estimated_error_z")
+ break
+ if not self.geo_keys:
+ # TODO....
+ pass
+
+ fields = OrderedDict()
+ for related_key in models.GeoVectorData.RELATED_MODELS:
+ model = models.GeoVectorData._meta.get_field(related_key).related_model
+ fields[related_key] = widgets.Select2MultipleField(
+ model=model,
+ remote=True,
+ label=model._meta.verbose_name_plural,
+ required=False,
+ style="width: 100%",
+ )
+ if related_key in main_items_fields:
+ for field_key, label in main_items_fields[related_key]:
+ disabled = False
+ if kwargs.get("initial", None) and kwargs["initial"].get(
+ field_key, False
+ ):
+ disabled = True
+ fields[field_key] = forms.BooleanField(
+ label=label, required=False, disabled=disabled
+ )
+ for k in self.geo_keys:
+ fields[k] = self.fields[k]
+ for k in self.fields:
+ if k not in self.geo_keys:
+ fields[k] = self.fields[k]
+ self.fields = fields
+
+ def get_headers(self):
+ headers = self.HEADERS.copy()
+ if self.geo_keys:
+ headers[self.geo_keys[0]] = headers.pop("geo_field")
+ return headers
+
+ def clean(self):
+ cleaned_data = self.cleaned_data
+ if "x" not in self.geo_keys:
+ # reverse...
+ geo_value = cleaned_data[self.geo_keys[0]]
+ if geo_value:
+ if not isinstance(geo_value, str):
+ geo_value = geo_value.ewkt
+ if geo_value.startswith("SRID=4326;"):
+ cleaned_data[self.geo_keys[0]] = reverse_coordinates(geo_value)
+ for rel in models.GeoVectorData.RELATED_MODELS:
+ if cleaned_data.get(rel, None):
+ return cleaned_data
+ raise forms.ValidationError(
+ _("A geo item has to be attached at least to one item")
+ )
+
+ def save(self, commit=True):
+ item = super().save(commit=commit)
+ for related_key in models.GeoVectorData.RELATED_MODELS:
+ related = getattr(item, related_key)
+ initial = dict([(rel.pk, rel) for rel in related.all()])
+ new = [int(pk) for pk in sorted(self.cleaned_data.get(related_key, []))]
+ for pk, value in initial.items():
+ if pk in new:
+ continue
+ related.remove(value)
+ for new_pk in new:
+ related_item = related.model.objects.get(pk=new_pk)
+ if new_pk not in initial.keys():
+ related.add(related_item)
+ item = models.GeoVectorData.objects.get(pk=item.pk)
+ if self.user:
+ item.history_creator = self.user
+ item.history_modifier = self.user
+ item.skip_history_when_saving = True
+ item.save() # resave to regen the attached items
+ return item