2021-07-01 13:36:07 +02:00
|
|
|
"""
|
|
|
|
Author: Michel Peltriaux
|
|
|
|
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
|
|
|
Contact: michel.peltriaux@sgdnord.rlp.de
|
|
|
|
Created on: 02.12.20
|
|
|
|
|
|
|
|
"""
|
|
|
|
from dal import autocomplete
|
|
|
|
from django import forms
|
|
|
|
from django.contrib.auth.models import User
|
|
|
|
from django.contrib.gis import forms as gis_forms
|
|
|
|
from django.contrib.gis.geos import Polygon
|
|
|
|
from django.db import transaction
|
|
|
|
from django.urls import reverse
|
|
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
|
|
|
|
from intervention.models import Intervention
|
2021-07-30 13:30:42 +02:00
|
|
|
from konova.forms import BaseForm, BaseModalForm
|
2021-07-01 13:36:07 +02:00
|
|
|
from konova.models import Document
|
2021-08-02 16:23:29 +02:00
|
|
|
from konova.settings import DEFAULT_LAT, DEFAULT_LON, DEFAULT_ZOOM, ZB_GROUP, ETS_GROUP
|
|
|
|
from konova.utils.user_checks import in_group
|
2021-07-01 13:36:07 +02:00
|
|
|
from organisation.models import Organisation
|
2021-08-03 17:22:41 +02:00
|
|
|
from user.models import UserActionLogEntry, UserAction
|
2021-07-01 13:36:07 +02:00
|
|
|
|
|
|
|
|
|
|
|
class NewInterventionForm(BaseForm):
|
|
|
|
identifier = forms.CharField(
|
|
|
|
label=_("Identifier"),
|
|
|
|
label_suffix="",
|
|
|
|
max_length=255,
|
|
|
|
help_text=_("Generated automatically if none was given"),
|
|
|
|
required=False,
|
|
|
|
)
|
|
|
|
title = forms.CharField(
|
|
|
|
label=_("Title"),
|
|
|
|
label_suffix="",
|
|
|
|
max_length=255,
|
|
|
|
)
|
|
|
|
type = forms.CharField(
|
|
|
|
label=_("Type"),
|
|
|
|
label_suffix="",
|
|
|
|
max_length=255,
|
|
|
|
help_text=_("Which intervention type is this"),
|
|
|
|
)
|
|
|
|
law = forms.CharField(
|
|
|
|
label=_("Law"),
|
|
|
|
label_suffix="",
|
|
|
|
max_length=255,
|
|
|
|
help_text=_("Based on which law"),
|
|
|
|
)
|
|
|
|
handler = forms.CharField(
|
|
|
|
label=_("Intervention handler"),
|
|
|
|
label_suffix="",
|
|
|
|
max_length=255,
|
|
|
|
help_text=_("Who performs the intervention"),
|
|
|
|
)
|
|
|
|
data_provider = forms.ModelChoiceField(
|
|
|
|
label=_("Data provider"),
|
|
|
|
label_suffix="",
|
|
|
|
help_text=_("Who provides the data for the intervention"),
|
|
|
|
queryset=Organisation.objects.all(),
|
|
|
|
widget=autocomplete.ModelSelect2(
|
|
|
|
url="other-orgs-autocomplete",
|
|
|
|
attrs={
|
|
|
|
"data-placeholder": _("Organization"),
|
|
|
|
"data-minimum-input-length": 3,
|
|
|
|
}
|
|
|
|
),
|
|
|
|
)
|
|
|
|
data_provider_detail = forms.CharField(
|
|
|
|
label=_("Data provider details"),
|
|
|
|
label_suffix="",
|
|
|
|
max_length=255,
|
|
|
|
help_text=_("Further details"),
|
|
|
|
required=False,
|
|
|
|
)
|
|
|
|
geometry = gis_forms.MultiPolygonField(
|
|
|
|
widget=gis_forms.OSMWidget(
|
|
|
|
attrs={
|
|
|
|
"default_lat": DEFAULT_LAT,
|
|
|
|
"default_lon": DEFAULT_LON,
|
|
|
|
"default_zoom": DEFAULT_ZOOM,
|
|
|
|
'map_width': 800,
|
|
|
|
'map_height': 500
|
|
|
|
},
|
|
|
|
),
|
|
|
|
label=_("Map"),
|
|
|
|
label_suffix="",
|
|
|
|
help_text=_("Where does the intervention take place")
|
|
|
|
)
|
|
|
|
documents = forms.FileField(
|
|
|
|
widget=forms.ClearableFileInput(
|
|
|
|
attrs={
|
|
|
|
"multiple": True,
|
|
|
|
}
|
|
|
|
),
|
|
|
|
label=_("Files"),
|
|
|
|
label_suffix="",
|
|
|
|
required=False,
|
|
|
|
)
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.form_title = _("New intervention")
|
|
|
|
self.action_url = reverse("intervention:new")
|
|
|
|
self.cancel_redirect = reverse("intervention:index")
|
|
|
|
|
|
|
|
def save(self, user: User):
|
|
|
|
with transaction.atomic():
|
|
|
|
identifier = self.cleaned_data.get("identifier", None)
|
|
|
|
title = self.cleaned_data.get("title", None)
|
|
|
|
_type = self.cleaned_data.get("type", None)
|
|
|
|
law = self.cleaned_data.get("law", None)
|
|
|
|
handler = self.cleaned_data.get("handler", None)
|
|
|
|
data_provider = self.cleaned_data.get("data_provider", None)
|
|
|
|
data_provider_detail = self.cleaned_data.get("data_provider_detail", None)
|
|
|
|
geometry = self.cleaned_data.get("geometry", Polygon())
|
|
|
|
documents = self.cleaned_data.get("documents", []) or []
|
|
|
|
|
2021-08-02 11:52:20 +02:00
|
|
|
action = UserActionLogEntry.objects.create(
|
|
|
|
user=user,
|
2021-08-03 17:22:41 +02:00
|
|
|
action=UserAction.CREATED,
|
2021-08-02 11:52:20 +02:00
|
|
|
)
|
2021-07-01 13:36:07 +02:00
|
|
|
intervention = Intervention(
|
|
|
|
identifier=identifier,
|
|
|
|
title=title,
|
|
|
|
type=_type,
|
|
|
|
law=law,
|
|
|
|
handler=handler,
|
|
|
|
data_provider=data_provider,
|
|
|
|
data_provider_detail=data_provider_detail,
|
|
|
|
geometry=geometry,
|
2021-08-02 11:52:20 +02:00
|
|
|
created=action,
|
2021-07-01 13:36:07 +02:00
|
|
|
)
|
|
|
|
intervention.save()
|
|
|
|
for doc in documents:
|
|
|
|
doc_obj = Document()
|
|
|
|
doc_obj.document = doc
|
|
|
|
# ToDo Add functionality for other attributes
|
|
|
|
doc_obj.save()
|
|
|
|
intervention.documents.add(doc_obj)
|
|
|
|
return intervention
|
|
|
|
|
|
|
|
|
|
|
|
class EditInterventionForm(NewInterventionForm):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
if self.instance is not None:
|
|
|
|
self.action_url = reverse("intervention:edit", args=(self.instance.id,))
|
|
|
|
self.cancel_redirect = reverse("intervention:index")
|
|
|
|
self.form_title = _("Edit intervention")
|
|
|
|
self.form_caption = ""
|
|
|
|
|
|
|
|
# Initialize form data
|
|
|
|
form_data = {
|
|
|
|
"identifier": self.instance.identifier,
|
|
|
|
"title": self.instance.title,
|
|
|
|
"type": self.instance.type,
|
|
|
|
"law": self.instance.law,
|
|
|
|
"handler": self.instance.handler,
|
|
|
|
"data_provider": self.instance.data_provider,
|
|
|
|
"data_provider_detail": self.instance.data_provider_detail,
|
|
|
|
"geometry": self.instance.geometry,
|
|
|
|
"documents": self.instance.documents.all(),
|
|
|
|
}
|
|
|
|
disabled_fields = [
|
|
|
|
"identifier",
|
|
|
|
]
|
|
|
|
self.load_initial_data(
|
|
|
|
form_data,
|
|
|
|
disabled_fields,
|
|
|
|
)
|
|
|
|
|
|
|
|
def save(self, user: User):
|
|
|
|
""" Overwrite instance with new form data
|
|
|
|
|
|
|
|
Args:
|
|
|
|
user ():
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
"""
|
|
|
|
with transaction.atomic():
|
|
|
|
identifier = self.cleaned_data.get("identifier", None)
|
|
|
|
title = self.cleaned_data.get("title", None)
|
|
|
|
_type = self.cleaned_data.get("type", None)
|
|
|
|
law = self.cleaned_data.get("law", None)
|
|
|
|
handler = self.cleaned_data.get("handler", None)
|
|
|
|
data_provider = self.cleaned_data.get("data_provider", None)
|
|
|
|
data_provider_detail = self.cleaned_data.get("data_provider_detail", None)
|
|
|
|
geometry = self.cleaned_data.get("geometry", Polygon())
|
|
|
|
documents = self.cleaned_data.get("documents", []) or []
|
|
|
|
|
|
|
|
self.instance.identifier = identifier
|
|
|
|
self.instance.title = title
|
|
|
|
self.instance.type = _type
|
|
|
|
self.instance.law = law
|
|
|
|
self.instance.handler = handler
|
|
|
|
self.instance.data_provider = data_provider
|
|
|
|
self.instance.data_provider_detail = data_provider_detail
|
|
|
|
self.instance.geometry = geometry
|
|
|
|
self.instance.save()
|
|
|
|
|
|
|
|
for doc in documents:
|
|
|
|
doc_obj = Document()
|
|
|
|
doc_obj.document = doc
|
|
|
|
# ToDo Add functionality for other attributes
|
|
|
|
doc_obj.save()
|
|
|
|
self.instance.documents.add(doc_obj)
|
|
|
|
return self.instance
|
|
|
|
|
|
|
|
|
|
|
|
class OpenInterventionForm(EditInterventionForm):
|
|
|
|
"""
|
|
|
|
This form is not intended to be used as data-input form. It's used to simplify the rendering of intervention:open
|
|
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
# Resize map
|
|
|
|
self.fields["geometry"].widget.attrs["map_width"] = 500
|
|
|
|
self.fields["geometry"].widget.attrs["map_height"] = 300
|
|
|
|
|
|
|
|
# Disable all form fields
|
|
|
|
for field in self.fields:
|
|
|
|
self.disable_form_field(field)
|
2021-07-28 09:53:14 +02:00
|
|
|
|
|
|
|
|
2021-07-30 14:34:36 +02:00
|
|
|
class DummyFilterInput(forms.HiddenInput):
|
|
|
|
""" A dummy input widget
|
|
|
|
|
|
|
|
Does not render anything. Can be used to keep filter logic using django_filter without having a pre defined
|
|
|
|
filter widget being rendered to the template.
|
|
|
|
|
|
|
|
"""
|
|
|
|
template_name = "konova/custom_widgets/dummy-filter-input.html"
|
|
|
|
|
|
|
|
|
|
|
|
class TextToClipboardInput(forms.TextInput):
|
|
|
|
template_name = "konova/custom_widgets/text-to-clipboard-input.html"
|
|
|
|
|
|
|
|
|
2021-07-30 13:30:42 +02:00
|
|
|
class ShareInterventionForm(BaseModalForm):
|
|
|
|
url = forms.CharField(
|
|
|
|
label=_("Share link"),
|
|
|
|
label_suffix="",
|
2021-07-30 15:23:46 +02:00
|
|
|
help_text=_("Send this link to users who you want to have writing access on the data"),
|
2021-07-30 13:30:42 +02:00
|
|
|
required=False,
|
2021-07-30 14:34:36 +02:00
|
|
|
widget=TextToClipboardInput(
|
2021-07-30 13:30:42 +02:00
|
|
|
attrs={
|
2021-07-30 14:34:36 +02:00
|
|
|
"readonly": True
|
2021-07-30 13:30:42 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
2021-07-30 15:23:46 +02:00
|
|
|
users = forms.MultipleChoiceField(
|
|
|
|
label=_("Shared with"),
|
|
|
|
label_suffix="",
|
|
|
|
required=True,
|
|
|
|
help_text=_("Remove check to remove access for this user"),
|
|
|
|
widget=forms.CheckboxSelectMultiple(
|
|
|
|
attrs={
|
|
|
|
"class": "list-unstyled",
|
|
|
|
}
|
|
|
|
),
|
|
|
|
choices=[]
|
|
|
|
)
|
2021-07-30 13:30:42 +02:00
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.form_title = _("Share")
|
2021-07-30 15:23:46 +02:00
|
|
|
self.form_caption = _("Share settings for {}").format(self.instance.identifier)
|
2021-07-30 13:30:42 +02:00
|
|
|
self.template = "modal/modal_form.html"
|
|
|
|
|
|
|
|
# Make sure an access_token is set
|
|
|
|
if self.instance.access_token is None:
|
|
|
|
self.instance.generate_access_token()
|
|
|
|
|
2021-07-30 15:23:46 +02:00
|
|
|
self._init_fields()
|
|
|
|
|
|
|
|
def _init_fields(self):
|
|
|
|
""" Wraps initializing of fields
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Initialize share_link field
|
2021-07-30 13:30:42 +02:00
|
|
|
self.share_link = self.request.build_absolute_uri(
|
|
|
|
reverse("intervention:share", args=(self.instance.id, self.instance.access_token,))
|
|
|
|
)
|
|
|
|
self.initialize_form_field(
|
|
|
|
"url",
|
|
|
|
self.share_link
|
|
|
|
)
|
2021-07-30 15:23:46 +02:00
|
|
|
|
|
|
|
# Initialize users field
|
2021-08-02 16:23:29 +02:00
|
|
|
# Remove field if user is not in registration or conservation group
|
|
|
|
if not in_group(self.request.user, ZB_GROUP) and not in_group(self.request.user, ETS_GROUP):
|
|
|
|
del self.fields["users"]
|
|
|
|
else:
|
|
|
|
users = self.instance.users.all()
|
|
|
|
choices = []
|
|
|
|
for n in users:
|
|
|
|
choices.append(
|
|
|
|
(n.id, n.username)
|
|
|
|
)
|
|
|
|
self.fields["users"].choices = choices
|
|
|
|
u_ids = list(users.values_list("id", flat=True))
|
|
|
|
self.initialize_form_field(
|
|
|
|
"users",
|
|
|
|
u_ids
|
2021-07-30 15:23:46 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
def save(self):
|
|
|
|
accessing_users = User.objects.filter(
|
|
|
|
id__in=self.cleaned_data["users"]
|
|
|
|
)
|
|
|
|
self.instance.users.set(accessing_users)
|