#7 New forms WIP

* adds saving functionality for new intervention form
* refactors new identifier generating, so a pre-generated identifier from a new element form will be checked again before saving
* adds css fixes for disturbing input field:focus bugs
* adds missing csrf token to new collapsible form
* adds/updates translations
* introduces mark_as_deleted as only marking instead of using delete() which will really delete from the db
This commit is contained in:
mipel
2021-09-23 15:05:17 +02:00
parent c43a5c243e
commit cb19c0f85d
11 changed files with 375 additions and 182 deletions

View File

@@ -13,8 +13,8 @@ from bootstrap_modal_forms.utils import is_ajax
from django import forms
from django.contrib import messages
from django.contrib.auth.models import User
from django.contrib.gis.forms import GeometryField, OSMWidget
from django.contrib.gis.geos import Polygon
from django.contrib.gis.forms import OSMWidget, MultiPolygonField
from django.contrib.gis.geos import Polygon, MultiPolygon
from django.db import transaction
from django.http import HttpRequest, HttpResponseRedirect
from django.shortcuts import render
@@ -25,7 +25,8 @@ from compensation.models import EcoAccount, Compensation, EcoAccountDocument, Co
from ema.models import Ema, EmaDocument
from intervention.models import Intervention, Revocation, RevocationDocument, InterventionDocument
from konova.contexts import BaseContext
from konova.models import BaseObject
from konova.models import BaseObject, Geometry
from konova.settings import DEFAULT_SRID
from konova.utils.message_templates import FORM_INVALID
from user.models import UserActionLogEntry, UserAction
@@ -187,8 +188,7 @@ class BaseModalForm(BaseForm, BSModalForm):
full_width_fields = False
template = "modal/modal_form.html"
def __init__(self, full_width_fields: bool = True, *args, **kwargs):
self.full_width_fields = full_width_fields
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.full_width_fields:
# Automatically add bootstrap w-100 class for maximum width of form fields in modals
@@ -243,18 +243,26 @@ class SimpleGeomForm(BaseForm):
""" A geometry form for rendering geometry read-only using a widget
"""
geom = GeometryField(
geom = MultiPolygonField(
srid=DEFAULT_SRID,
label=_("Geometry"),
help_text=_(""),
label_suffix="",
required=False,
disabled=True,
disabled=False,
widget=OSMWidget(
attrs={
"map_width": 600,
"map_height": 400,
# default_zoom defines the nearest possible zoom level from which the JS automatically
# zooms out if geometry requires a larger view port. So define a larger range for smaller geometries
"default_zoom": 25,
}
)
)
def __init__(self, *args, **kwargs):
read_only = kwargs.pop("read_only", True)
super().__init__(*args, **kwargs)
# Initialize geometry
@@ -267,8 +275,17 @@ class SimpleGeomForm(BaseForm):
geom = Polygon.from_bbox([0, 0, 0, 0])
# Zoom out to a very high level, so the user can see directly that there is no geometry for this entry
self.fields["geom"].widget.attrs["default_zoom"] = 1
self.initialize_form_field("geom", geom)
self.area = geom.area
if read_only:
self.initialize_form_field("geom", geom)
self.area = geom.area
self.fields["geom"].disabled = True
def save(self, action: UserActionLogEntry):
geometry = Geometry.objects.create(
geom=self.cleaned_data.get("geom", MultiPolygon(srid=DEFAULT_SRID)),
created=action,
)
return geometry
class RemoveModalForm(BaseModalForm):
@@ -294,15 +311,7 @@ class RemoveModalForm(BaseModalForm):
def save(self):
if isinstance(self.instance, BaseObject):
with transaction.atomic():
action = UserActionLogEntry.objects.create(
user=self.user,
timestamp=timezone.now(),
action=UserAction.DELETED,
)
self.instance.deleted = action
self.instance.log.add(action)
self.instance.save()
self.instance.mark_as_deleted(self.user)
else:
# If the class does not provide restorable delete functionality, we must delete the entry finally
self.instance.delete()
@@ -360,6 +369,9 @@ class NewDocumentForm(BaseModalForm):
Ema: EmaDocument,
}
# Define w-100 for all form fields
full_width_fields = True
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("Add new document")

View File

@@ -9,6 +9,8 @@ import os
import uuid
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.utils import timezone
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from django.contrib.gis.db.models import MultiPolygonField
@@ -61,8 +63,20 @@ class BaseResource(UuidModel):
abstract = True
def delete(self, using=None, keep_parents=False):
if self.created:
""" Base deletin of a resource
Args:
using ():
keep_parents ():
Returns:
"""
try:
self.created.delete()
except ObjectDoesNotExist:
# Object does not exist anymore - we can skip this
pass
super().delete()
@@ -81,14 +95,13 @@ class BaseObject(BaseResource):
class Meta:
abstract = True
def delete(self, *args, **kwargs):
""" Custom delete functionality
def mark_as_deleted(self, user: User):
""" Mark an entry as deleted
Does not delete from database but sets a timestamp for being deleted on and which user deleted the object
Args:
*args ():
**kwargs ():
user (User): The performing user
Returns:
@@ -97,13 +110,14 @@ class BaseObject(BaseResource):
# Nothing to do here
return
_user = kwargs.get("user", None)
with transaction.atomic():
action = UserActionLogEntry.objects.create(
user=_user,
action=UserAction.DELETED
user=user,
action=UserAction.DELETED,
timestamp=timezone.now()
)
self.deleted = action
self.log.add(action)
self.save()
def add_log_entry(self, action: UserAction, user: User, comment: str):

View File

@@ -60,8 +60,18 @@ a {
color: var(--rlp-red);
}
input[type=text] {
width: 100%;
input[type=text], input[type=date] {
border: 1px solid gray;
border-radius: 0.2rem;
padding: 0.3rem 0.5rem;
}
input:focus, textarea:focus, select:focus{
outline: none;
border-color: var(--rlp-red);
box-shadow: 0 0 3px var(--rlp-red);
-moz-box-shadow: 0 0 3px var(--rlp-red);
-webkit-box-shadow: 0 0 3px var(--rlp-red);
}
.body-content{
@@ -137,6 +147,13 @@ input[type=text] {
height: 8rem;
}
/**
Overwrites bootstrap .btn:focus box shadow color
*/
.btn:focus{
box-shadow: 0 0 5px .2rem var(--rlp-gray-light);
}
.btn-default{
color: white;
background-color: var(--rlp-red);
@@ -175,13 +192,6 @@ input[type=text] {
background-color: var(--rlp-gray-light);
}
input:focus, textarea:focus, select:focus{
border-color: var(--rlp-red) !important;
box-shadow: 0 0 3px var(--rlp-red) !important;
-moz-box-shadow: 0 0 3px var(--rlp-red) !important;
-webkit-box-shadow: 0 0 3px var(--rlp-red) !important;
}
.check-star{
color: goldenrod;
}
@@ -219,4 +229,7 @@ No other approach worked to get the autocomplete fields to full width of parent
*/
.select2-container{
width: 100% !important;
}
.select2-results__option--highlighted{
background-color: var(--rlp-red) !important;
}