You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
konova/intervention/forms.py

424 lines
14 KiB
Python

"""
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, Revocation
from konova.forms import BaseForm, BaseModalForm
from konova.models import Document
from konova.settings import DEFAULT_LAT, DEFAULT_LON, DEFAULT_ZOOM, ZB_GROUP, ETS_GROUP
from konova.utils.user_checks import in_group
from organisation.models import Organisation
from user.models import UserActionLogEntry, UserAction
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 []
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.CREATED,
)
intervention = Intervention(
identifier=identifier,
title=title,
type=_type,
law=law,
handler=handler,
data_provider=data_provider,
data_provider_detail=data_provider_detail,
geometry=geometry,
created=action,
)
intervention.save()
for doc in documents:
doc_obj = Document()
doc_obj.file = 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)
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"
class ShareInterventionForm(BaseModalForm):
url = forms.CharField(
label=_("Share link"),
label_suffix="",
help_text=_("Send this link to users who you want to have writing access on the data"),
required=False,
widget=TextToClipboardInput(
attrs={
"readonly": True
}
)
)
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=[]
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("Share")
self.form_caption = _("Share settings for {}").format(self.instance.identifier)
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()
self._init_fields()
def _init_fields(self):
""" Wraps initializing of fields
Returns:
"""
# Initialize share_link field
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
)
# Initialize users field
# 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
)
def save(self):
accessing_users = User.objects.filter(
id__in=self.cleaned_data["users"]
)
self.instance.users.set(accessing_users)
class NewRevocationForm(BaseModalForm):
date = forms.DateField(
label=_("Date"),
label_suffix=_(""),
help_text=_("Date of revocation"),
widget=forms.DateInput(
attrs={
"type": "date",
"data-provide": "datepicker",
},
format="%d.%m.%Y"
)
)
file = forms.FileField(
label=_("Document"),
label_suffix=_(""),
help_text=_("Must be smaller than 15 Mb"),
widget=forms.FileInput(
attrs={
"class": "w-75"
}
)
)
comment = forms.CharField(
required=False,
max_length=200,
label=_("Comment"),
label_suffix=_(""),
help_text=_("Additional comment, maximum {} letters").format(200),
widget=forms.Textarea(
attrs={
"cols": 30,
"rows": 5,
}
)
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("Add revocation")
self.form_caption = ""
self.form_attrs = {
"enctype": "multipart/form-data", # important for file upload
}
def save(self):
with transaction.atomic():
user_action = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.CREATED
)
document = Document.objects.create(
title="revocation_of_{}".format(self.instance.identifier),
date_of_creation=self.cleaned_data["date"],
comment=self.cleaned_data["comment"],
file=self.cleaned_data["file"],
)
revocation = Revocation.objects.create(
date=self.cleaned_data["date"],
comment=self.cleaned_data["comment"],
document=document,
created=user_action,
)
self.instance.legal.revocation = revocation
self.instance.legal.save()
return revocation
class RunCheckForm(BaseModalForm):
checked_intervention = forms.BooleanField(
label=_("Checked intervention data"),
label_suffix="",
widget=forms.CheckboxInput(),
required=True,
)
checked_comps = forms.BooleanField(
label=_("Checked compensations data and payments"),
label_suffix="",
widget=forms.CheckboxInput(),
required=True
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("Run check")
self.form_caption = _("I, {} {}, confirm that all necessary control steps have been performed by myself.").format(self.user.first_name, self.user.last_name)
def is_valid(self):
super_result = super().is_valid()
# Perform check
result, msgs = self.instance.check_validity()
self.errors.update(msgs)
return result & super_result
def save(self):
with transaction.atomic():
user_action = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.CHECKED
)
# Replace old checked
if self.instance.checked:
self.instance.checked.delete()
self.instance.checked = user_action
self.instance.save()