Compare commits
36 Commits
master
...
490_View_r
| Author | SHA1 | Date | |
|---|---|---|---|
| cf6f188ef3 | |||
| f122778232 | |||
| bc2e901ca9 | |||
| 4a16727da1 | |||
| d85ebccec8 | |||
| 837c1de938 | |||
| fe2ac3d97d | |||
| 554ade6794 | |||
| 3a9c4e13f6 | |||
| 1fc1b533cd | |||
| 1175fe3b37 | |||
| d2a57df080 | |||
| d5accb2143 | |||
| 6056a8882d | |||
| c7a4c309bf | |||
| a7b23935a1 | |||
| 97fbe02742 | |||
| ed5d571704 | |||
| a86d86b731 | |||
| 73178b3fd2 | |||
| 278a951e92 | |||
| 9e4a78ec60 | |||
| d03b714fb5 | |||
| a9b402862b | |||
| 61ec9c8c9b | |||
| f2baa054bf | |||
| 242730435e | |||
| afbdf221c3 | |||
| be9f6f1b7e | |||
| 80e8925a63 | |||
| c597e1934b | |||
| a44d8658d4 | |||
| bb71c0fcc8 | |||
| 67acddf701 | |||
| 21bb988d86 | |||
| 1ceffccd40 |
@ -168,6 +168,17 @@ class NewCompensationForm(AbstractCompensationForm,
|
|||||||
comp.log.add(action)
|
comp.log.add(action)
|
||||||
return comp, action
|
return comp, action
|
||||||
|
|
||||||
|
def is_valid(self):
|
||||||
|
valid = super().is_valid()
|
||||||
|
intervention = self.cleaned_data.get("intervention", None)
|
||||||
|
if intervention.is_recorded:
|
||||||
|
valid &= False
|
||||||
|
self.add_error(
|
||||||
|
"intervention",
|
||||||
|
_("This intervention is currently recorded. You cannot add further compensations as long as it is recorded.")
|
||||||
|
)
|
||||||
|
return valid
|
||||||
|
|
||||||
def save(self, user: User, geom_form: SimpleGeomForm):
|
def save(self, user: User, geom_form: SimpleGeomForm):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
comp, action = self.__create_comp(user)
|
comp, action = self.__create_comp(user)
|
||||||
|
|||||||
@ -7,10 +7,12 @@ Created on: 18.08.22
|
|||||||
"""
|
"""
|
||||||
from dal import autocomplete
|
from dal import autocomplete
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from codelist.models import KonovaCode
|
from codelist.models import KonovaCode
|
||||||
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_COMPENSATION_ACTION_DETAIL_ID
|
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_COMPENSATION_ACTION_DETAIL_ID
|
||||||
|
from compensation.models import CompensationAction
|
||||||
from intervention.inputs import CompensationActionTreeCheckboxSelectMultiple
|
from intervention.inputs import CompensationActionTreeCheckboxSelectMultiple
|
||||||
from konova.forms.modals import BaseModalForm, RemoveModalForm
|
from konova.forms.modals import BaseModalForm, RemoveModalForm
|
||||||
from konova.utils.message_templates import COMPENSATION_ACTION_EDITED, ADDED_COMPENSATION_ACTION
|
from konova.utils.message_templates import COMPENSATION_ACTION_EDITED, ADDED_COMPENSATION_ACTION
|
||||||
@ -114,7 +116,8 @@ class EditCompensationActionModalForm(NewCompensationActionModalForm):
|
|||||||
action = None
|
action = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.action = kwargs.pop("action", None)
|
action_id = kwargs.pop("action_id", None)
|
||||||
|
self.action = get_object_or_404(CompensationAction, id=action_id)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.form_title = _("Edit action")
|
self.form_title = _("Edit action")
|
||||||
form_data = {
|
form_data = {
|
||||||
@ -147,8 +150,8 @@ class RemoveCompensationActionModalForm(RemoveModalForm):
|
|||||||
action = None
|
action = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
action = kwargs.pop("action", None)
|
action_id = kwargs.pop("action_id", None)
|
||||||
self.action = action
|
self.action = get_object_or_404(CompensationAction, id=action_id)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
|||||||
@ -6,10 +6,11 @@ Created on: 18.08.22
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from konova.forms.modals import BaseModalForm
|
from konova.forms.modals import BaseModalForm
|
||||||
from konova.models import DeadlineType
|
from konova.models import DeadlineType, Deadline
|
||||||
from konova.utils import validators
|
from konova.utils import validators
|
||||||
from konova.utils.message_templates import DEADLINE_EDITED
|
from konova.utils.message_templates import DEADLINE_EDITED
|
||||||
|
|
||||||
@ -90,7 +91,8 @@ class EditDeadlineModalForm(NewDeadlineModalForm):
|
|||||||
deadline = None
|
deadline = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.deadline = kwargs.pop("deadline", None)
|
deadline_id = kwargs.pop("deadline_id", None)
|
||||||
|
self.deadline = get_object_or_404(Deadline, id=deadline_id)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.form_title = _("Edit deadline")
|
self.form_title = _("Edit deadline")
|
||||||
form_data = {
|
form_data = {
|
||||||
|
|||||||
@ -6,12 +6,27 @@ Created on: 18.08.22
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from compensation.models import CompensationDocument, EcoAccountDocument
|
from compensation.models import CompensationDocument, EcoAccountDocument
|
||||||
from konova.forms.modals import NewDocumentModalForm
|
from konova.forms.modals import NewDocumentModalForm, EditDocumentModalForm, RemoveDocumentModalForm
|
||||||
|
|
||||||
|
|
||||||
class NewCompensationDocumentModalForm(NewDocumentModalForm):
|
class NewCompensationDocumentModalForm(NewDocumentModalForm):
|
||||||
document_model = CompensationDocument
|
_DOCUMENT_CLS = CompensationDocument
|
||||||
|
|
||||||
|
|
||||||
|
class EditCompensationDocumentModalForm(EditDocumentModalForm):
|
||||||
|
_DOCUMENT_CLS = CompensationDocument
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveCompensationDocumentModalForm(RemoveDocumentModalForm):
|
||||||
|
_DOCUMENT_CLS = CompensationDocument
|
||||||
|
|
||||||
|
|
||||||
class NewEcoAccountDocumentModalForm(NewDocumentModalForm):
|
class NewEcoAccountDocumentModalForm(NewDocumentModalForm):
|
||||||
document_model = EcoAccountDocument
|
_DOCUMENT_CLS = EcoAccountDocument
|
||||||
|
|
||||||
|
class EditEcoAccountDocumentModalForm(EditDocumentModalForm):
|
||||||
|
_DOCUMENT_CLS = EcoAccountDocument
|
||||||
|
|
||||||
|
class RemoveEcoAccountDocumentModalForm(RemoveDocumentModalForm):
|
||||||
|
_DOCUMENT_CLS = EcoAccountDocument
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,10 @@ Created on: 18.08.22
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.translation import pgettext_lazy as _con, gettext_lazy as _
|
from django.utils.translation import pgettext_lazy as _con, gettext_lazy as _
|
||||||
|
|
||||||
|
from compensation.models import Payment
|
||||||
from konova.forms.modals import RemoveModalForm, BaseModalForm
|
from konova.forms.modals import RemoveModalForm, BaseModalForm
|
||||||
from konova.utils import validators
|
from konova.utils import validators
|
||||||
from konova.utils.message_templates import PAYMENT_EDITED
|
from konova.utils.message_templates import PAYMENT_EDITED
|
||||||
@ -103,7 +105,8 @@ class EditPaymentModalForm(NewPaymentForm):
|
|||||||
payment = None
|
payment = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.payment = kwargs.pop("payment", None)
|
payment_id = kwargs.pop("payment_id", None)
|
||||||
|
self.payment = get_object_or_404(Payment, id=payment_id)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.form_title = _("Edit payment")
|
self.form_title = _("Edit payment")
|
||||||
form_date = {
|
form_date = {
|
||||||
@ -133,8 +136,8 @@ class RemovePaymentModalForm(RemoveModalForm):
|
|||||||
payment = None
|
payment = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
payment = kwargs.pop("payment", None)
|
payment_id = kwargs.pop("payment_id", None)
|
||||||
self.payment = payment
|
self.payment = get_object_or_404(Payment, id=payment_id)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
|||||||
15
compensation/forms/modals/resubmission.py
Normal file
15
compensation/forms/modals/resubmission.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
"""
|
||||||
|
Author: Michel Peltriaux
|
||||||
|
Created on: 21.10.25
|
||||||
|
|
||||||
|
"""
|
||||||
|
from compensation.models import Compensation, EcoAccount
|
||||||
|
from konova.forms.modals import ResubmissionModalForm
|
||||||
|
|
||||||
|
|
||||||
|
class CompensationResubmissionModalForm(ResubmissionModalForm):
|
||||||
|
_MODEL_CLS = Compensation
|
||||||
|
|
||||||
|
|
||||||
|
class EcoAccountResubmissionModalForm(ResubmissionModalForm):
|
||||||
|
_MODEL_CLS = EcoAccount
|
||||||
@ -5,21 +5,17 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 18.08.22
|
Created on: 18.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from bootstrap_modal_forms.mixins import is_ajax
|
|
||||||
from dal import autocomplete
|
from dal import autocomplete
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import messages
|
|
||||||
from django.http import HttpResponseRedirect, HttpRequest
|
|
||||||
from django.shortcuts import render
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from codelist.models import KonovaCode
|
from codelist.models import KonovaCode
|
||||||
from codelist.settings import CODELIST_BIOTOPES_ID, \
|
from codelist.settings import CODELIST_BIOTOPES_ID, \
|
||||||
CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID
|
CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID
|
||||||
|
from compensation.models import CompensationState
|
||||||
from intervention.inputs import CompensationStateTreeRadioSelect
|
from intervention.inputs import CompensationStateTreeRadioSelect
|
||||||
from konova.contexts import BaseContext
|
|
||||||
from konova.forms.modals import RemoveModalForm, BaseModalForm
|
from konova.forms.modals import RemoveModalForm, BaseModalForm
|
||||||
from konova.utils.message_templates import COMPENSATION_STATE_EDITED, FORM_INVALID, ADDED_COMPENSATION_STATE
|
from konova.utils.message_templates import COMPENSATION_STATE_EDITED, ADDED_COMPENSATION_STATE
|
||||||
|
|
||||||
|
|
||||||
class NewCompensationStateModalForm(BaseModalForm):
|
class NewCompensationStateModalForm(BaseModalForm):
|
||||||
@ -68,10 +64,13 @@ class NewCompensationStateModalForm(BaseModalForm):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_is_before_state: bool = False
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.form_title = _("New state")
|
self.form_title = _("New state")
|
||||||
self.form_caption = _("Insert data for the new state")
|
self.form_caption = _("Insert data for the new state")
|
||||||
|
self._is_before_state = bool(self.request.GET.get("before", False))
|
||||||
choices = KonovaCode.objects.filter(
|
choices = KonovaCode.objects.filter(
|
||||||
code_lists__in=[CODELIST_BIOTOPES_ID],
|
code_lists__in=[CODELIST_BIOTOPES_ID],
|
||||||
is_archived=False,
|
is_archived=False,
|
||||||
@ -83,65 +82,19 @@ class NewCompensationStateModalForm(BaseModalForm):
|
|||||||
]
|
]
|
||||||
self.fields["biotope_type"].choices = choices
|
self.fields["biotope_type"].choices = choices
|
||||||
|
|
||||||
def save(self, is_before_state: bool = False):
|
def save(self):
|
||||||
state = self.instance.add_state(self, is_before_state)
|
state = self.instance.add_state(self, self._is_before_state)
|
||||||
self.instance.mark_as_edited(self.user, self.request, ADDED_COMPENSATION_STATE)
|
self.instance.mark_as_edited(self.user, self.request, ADDED_COMPENSATION_STATE)
|
||||||
return state
|
return state
|
||||||
|
|
||||||
def process_request(self, request: HttpRequest, msg_success: str = _("Object removed"), msg_error: str = FORM_INVALID, redirect_url: str = None):
|
|
||||||
""" Generic processing of request
|
|
||||||
|
|
||||||
Wraps the request processing logic, so we don't need the same code everywhere a RemoveModalForm is being used
|
|
||||||
|
|
||||||
+++
|
|
||||||
The generic method from super class can not be used, since we need to do some request parameter check in here.
|
|
||||||
+++
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
msg_success (str): The message in case of successful removing
|
|
||||||
msg_error (str): The message in case of an error
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
redirect_url = redirect_url if redirect_url is not None else request.META.get("HTTP_REFERER", "home")
|
|
||||||
template = self.template
|
|
||||||
if request.method == "POST":
|
|
||||||
if self.is_valid():
|
|
||||||
# Modal forms send one POST for checking on data validity. This can be used to return possible errors
|
|
||||||
# on the form. A second POST (if no errors occured) is sent afterwards and needs to process the
|
|
||||||
# saving/commiting of the data to the database. is_ajax() performs this check. The first request is
|
|
||||||
# an ajax call, the second is a regular form POST.
|
|
||||||
if not is_ajax(request.META):
|
|
||||||
is_before_state = bool(request.GET.get("before", False))
|
|
||||||
self.save(is_before_state=is_before_state)
|
|
||||||
messages.success(
|
|
||||||
request,
|
|
||||||
msg_success
|
|
||||||
)
|
|
||||||
return HttpResponseRedirect(redirect_url)
|
|
||||||
else:
|
|
||||||
context = {
|
|
||||||
"form": self,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
elif request.method == "GET":
|
|
||||||
context = {
|
|
||||||
"form": self,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
else:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
class EditCompensationStateModalForm(NewCompensationStateModalForm):
|
class EditCompensationStateModalForm(NewCompensationStateModalForm):
|
||||||
state = None
|
state = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.state = kwargs.pop("state", None)
|
state_id = kwargs.pop("state_id", None)
|
||||||
|
self.state = CompensationState.objects.get(id=state_id)
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.form_title = _("Edit state")
|
self.form_title = _("Edit state")
|
||||||
biotope_type_id = self.state.biotope_type.id if self.state.biotope_type else None
|
biotope_type_id = self.state.biotope_type.id if self.state.biotope_type else None
|
||||||
@ -172,8 +125,8 @@ class RemoveCompensationStateModalForm(RemoveModalForm):
|
|||||||
state = None
|
state = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
state = kwargs.pop("state", None)
|
state_id = kwargs.pop("state_id", None)
|
||||||
self.state = state
|
self.state = CompensationState.objects.get(id=state_id)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
|||||||
@ -80,7 +80,11 @@ class EditCompensationActionModalFormTestCase(NewCompensationActionModalFormTest
|
|||||||
self.compensation.actions.add(self.comp_action)
|
self.compensation.actions.add(self.comp_action)
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
form = EditCompensationActionModalForm(request=self.request, instance=self.compensation, action=self.comp_action)
|
form = EditCompensationActionModalForm(
|
||||||
|
request=self.request,
|
||||||
|
instance=self.compensation,
|
||||||
|
action_id=self.comp_action.id
|
||||||
|
)
|
||||||
self.assertEqual(form.form_title, str(_("Edit action")))
|
self.assertEqual(form.form_title, str(_("Edit action")))
|
||||||
self.assertEqual(len(form.fields["action_type"].initial), self.comp_action.action_type.count())
|
self.assertEqual(len(form.fields["action_type"].initial), self.comp_action.action_type.count())
|
||||||
self.assertEqual(len(form.fields["action_type_details"].initial), self.comp_action.action_type_details.count())
|
self.assertEqual(len(form.fields["action_type_details"].initial), self.comp_action.action_type_details.count())
|
||||||
@ -101,7 +105,7 @@ class EditCompensationActionModalFormTestCase(NewCompensationActionModalFormTest
|
|||||||
"comment": comment,
|
"comment": comment,
|
||||||
}
|
}
|
||||||
|
|
||||||
form = EditCompensationActionModalForm(data, request=self.request, instance=self.compensation, action=self.comp_action)
|
form = EditCompensationActionModalForm(data, request=self.request, instance=self.compensation, action_id=self.comp_action.id)
|
||||||
|
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
action = form.save()
|
action = form.save()
|
||||||
@ -126,7 +130,7 @@ class RemoveCompensationActionModalFormTestCase(EditCompensationActionModalFormT
|
|||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
self.assertIn(self.comp_action, self.compensation.actions.all())
|
self.assertIn(self.comp_action, self.compensation.actions.all())
|
||||||
form = RemoveCompensationActionModalForm(request=self.request, instance=self.compensation, action=self.comp_action)
|
form = RemoveCompensationActionModalForm(request=self.request, instance=self.compensation, action_id=self.comp_action.id)
|
||||||
self.assertEqual(form.action, self.comp_action)
|
self.assertEqual(form.action, self.comp_action)
|
||||||
|
|
||||||
def test_save(self):
|
def test_save(self):
|
||||||
@ -137,7 +141,7 @@ class RemoveCompensationActionModalFormTestCase(EditCompensationActionModalFormT
|
|||||||
data,
|
data,
|
||||||
request=self.request,
|
request=self.request,
|
||||||
instance=self.compensation,
|
instance=self.compensation,
|
||||||
action=self.comp_action
|
action_id=self.comp_action.id
|
||||||
)
|
)
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
self.assertIn(self.comp_action, self.compensation.actions.all())
|
self.assertIn(self.comp_action, self.compensation.actions.all())
|
||||||
@ -186,12 +190,20 @@ class NewCompensationStateModalFormTestCase(BaseTestCase):
|
|||||||
self.assertEqual(self.compensation.before_states.count(), 0)
|
self.assertEqual(self.compensation.before_states.count(), 0)
|
||||||
self.assertEqual(self.compensation.after_states.count(), 0)
|
self.assertEqual(self.compensation.after_states.count(), 0)
|
||||||
|
|
||||||
form = NewCompensationStateModalForm(data, request=self.request, instance=self.compensation)
|
self.request.GET._mutable = True
|
||||||
|
self.request.GET.update(
|
||||||
|
{
|
||||||
|
"before": True,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.request.GET._mutable = False
|
||||||
|
form = NewCompensationStateModalForm(
|
||||||
|
data,
|
||||||
|
request=self.request,
|
||||||
|
instance=self.compensation,
|
||||||
|
)
|
||||||
self.assertTrue(form.is_valid(), msg=form.errors)
|
self.assertTrue(form.is_valid(), msg=form.errors)
|
||||||
|
state = form.save()
|
||||||
is_before_state = True
|
|
||||||
state = form.save(is_before_state)
|
|
||||||
|
|
||||||
self.assertEqual(self.compensation.before_states.count(), 1)
|
self.assertEqual(self.compensation.before_states.count(), 1)
|
||||||
self.assertEqual(self.compensation.after_states.count(), 0)
|
self.assertEqual(self.compensation.after_states.count(), 0)
|
||||||
@ -205,8 +217,16 @@ class NewCompensationStateModalFormTestCase(BaseTestCase):
|
|||||||
self.assertEqual(last_log.action, UserAction.EDITED)
|
self.assertEqual(last_log.action, UserAction.EDITED)
|
||||||
self.assertEqual(last_log.comment, ADDED_COMPENSATION_STATE)
|
self.assertEqual(last_log.comment, ADDED_COMPENSATION_STATE)
|
||||||
|
|
||||||
is_before_state = False
|
self.request.GET._mutable = True
|
||||||
state = form.save(is_before_state)
|
del self.request.GET["before"]
|
||||||
|
self.request.GET._mutable = False
|
||||||
|
form = NewCompensationStateModalForm(
|
||||||
|
data,
|
||||||
|
request=self.request,
|
||||||
|
instance=self.compensation,
|
||||||
|
)
|
||||||
|
self.assertTrue(form.is_valid(), msg=form.errors)
|
||||||
|
state = form.save()
|
||||||
|
|
||||||
self.assertEqual(self.compensation.before_states.count(), 1)
|
self.assertEqual(self.compensation.before_states.count(), 1)
|
||||||
self.assertEqual(self.compensation.after_states.count(), 1)
|
self.assertEqual(self.compensation.after_states.count(), 1)
|
||||||
@ -230,7 +250,11 @@ class EditCompensationStateModalFormTestCase(NewCompensationStateModalFormTestCa
|
|||||||
self.compensation.after_states.add(self.comp_state)
|
self.compensation.after_states.add(self.comp_state)
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
form = EditCompensationStateModalForm(request=self.request, instance=self.compensation, state=self.comp_state)
|
form = EditCompensationStateModalForm(
|
||||||
|
request=self.request,
|
||||||
|
instance=self.compensation,
|
||||||
|
state_id=self.comp_state.id
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(form.state, self.comp_state)
|
self.assertEqual(form.state, self.comp_state)
|
||||||
self.assertEqual(form.form_title, str(_("Edit state")))
|
self.assertEqual(form.form_title, str(_("Edit state")))
|
||||||
@ -261,7 +285,7 @@ class EditCompensationStateModalFormTestCase(NewCompensationStateModalFormTestCa
|
|||||||
data,
|
data,
|
||||||
request=self.request,
|
request=self.request,
|
||||||
instance=self.compensation,
|
instance=self.compensation,
|
||||||
state=self.comp_state
|
state_id=self.comp_state.id
|
||||||
)
|
)
|
||||||
self.assertTrue(form.is_valid(), msg=form.errors)
|
self.assertTrue(form.is_valid(), msg=form.errors)
|
||||||
|
|
||||||
@ -282,7 +306,11 @@ class RemoveCompensationStateModalFormTestCase(EditCompensationStateModalFormTes
|
|||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
form = RemoveCompensationStateModalForm(request=self.request, instance=self.compensation, state=self.comp_state)
|
form = RemoveCompensationStateModalForm(
|
||||||
|
request=self.request,
|
||||||
|
instance=self.compensation,
|
||||||
|
state_id=self.comp_state.id
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(form.state, self.comp_state)
|
self.assertEqual(form.state, self.comp_state)
|
||||||
|
|
||||||
@ -294,7 +322,7 @@ class RemoveCompensationStateModalFormTestCase(EditCompensationStateModalFormTes
|
|||||||
data,
|
data,
|
||||||
request=self.request,
|
request=self.request,
|
||||||
instance=self.compensation,
|
instance=self.compensation,
|
||||||
state=self.comp_state
|
state_id=self.comp_state.id
|
||||||
)
|
)
|
||||||
self.assertTrue(form.is_valid(), msg=form.errors)
|
self.assertTrue(form.is_valid(), msg=form.errors)
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class AbstractCompensationModelTestCase(BaseTestCase):
|
|||||||
data,
|
data,
|
||||||
request=self.request,
|
request=self.request,
|
||||||
instance=self.compensation,
|
instance=self.compensation,
|
||||||
deadline=self.finished_deadline,
|
deadline_id=self.finished_deadline.id,
|
||||||
)
|
)
|
||||||
self.assertTrue(form.is_valid(), msg=form.errors)
|
self.assertTrue(form.is_valid(), msg=form.errors)
|
||||||
self.assertIn(self.finished_deadline, self.compensation.deadlines.all())
|
self.assertIn(self.finished_deadline, self.compensation.deadlines.all())
|
||||||
|
|||||||
@ -10,27 +10,28 @@ from django.urls import path
|
|||||||
from compensation.views.compensation.document import EditCompensationDocumentView, NewCompensationDocumentView, \
|
from compensation.views.compensation.document import EditCompensationDocumentView, NewCompensationDocumentView, \
|
||||||
GetCompensationDocumentView, RemoveCompensationDocumentView
|
GetCompensationDocumentView, RemoveCompensationDocumentView
|
||||||
from compensation.views.compensation.resubmission import CompensationResubmissionView
|
from compensation.views.compensation.resubmission import CompensationResubmissionView
|
||||||
from compensation.views.compensation.report import report_view
|
from compensation.views.compensation.report import CompensationReportView
|
||||||
from compensation.views.compensation.deadline import NewCompensationDeadlineView, EditCompensationDeadlineView, \
|
from compensation.views.compensation.deadline import NewCompensationDeadlineView, EditCompensationDeadlineView, \
|
||||||
RemoveCompensationDeadlineView
|
RemoveCompensationDeadlineView
|
||||||
from compensation.views.compensation.action import NewCompensationActionView, EditCompensationActionView, \
|
from compensation.views.compensation.action import NewCompensationActionView, EditCompensationActionView, \
|
||||||
RemoveCompensationActionView
|
RemoveCompensationActionView
|
||||||
from compensation.views.compensation.state import NewCompensationStateView, EditCompensationStateView, \
|
from compensation.views.compensation.state import NewCompensationStateView, EditCompensationStateView, \
|
||||||
RemoveCompensationStateView
|
RemoveCompensationStateView
|
||||||
from compensation.views.compensation.compensation import index_view, new_view, new_id_view, detail_view, edit_view, \
|
from compensation.views.compensation.compensation import \
|
||||||
remove_view
|
CompensationIndexView, CompensationIdentifierGeneratorView, CompensationDetailView, \
|
||||||
|
NewCompensationFormView, EditCompensationFormView, RemoveCompensationView
|
||||||
from compensation.views.compensation.log import CompensationLogView
|
from compensation.views.compensation.log import CompensationLogView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# Main compensation
|
# Main compensation
|
||||||
path("", index_view, name="index"),
|
path("", CompensationIndexView.as_view(), name="index"),
|
||||||
path('new/id', new_id_view, name='new-id'),
|
path('new/id', CompensationIdentifierGeneratorView.as_view(), name='new-id'),
|
||||||
path('new/<intervention_id>', new_view, name='new'),
|
path('new/<intervention_id>', NewCompensationFormView.as_view(), name='new'),
|
||||||
path('new', new_view, name='new'),
|
path('new', NewCompensationFormView.as_view(), name='new'),
|
||||||
path('<id>', detail_view, name='detail'),
|
path('<id>', CompensationDetailView.as_view(), name='detail'),
|
||||||
path('<id>/log', CompensationLogView.as_view(), name='log'),
|
path('<id>/log', CompensationLogView.as_view(), name='log'),
|
||||||
path('<id>/edit', edit_view, name='edit'),
|
path('<id>/edit', EditCompensationFormView.as_view(), name='edit'),
|
||||||
path('<id>/remove', remove_view, name='remove'),
|
path('<id>/remove', RemoveCompensationView.as_view(), name='remove'),
|
||||||
|
|
||||||
path('<id>/state/new', NewCompensationStateView.as_view(), name='new-state'),
|
path('<id>/state/new', NewCompensationStateView.as_view(), name='new-state'),
|
||||||
path('<id>/state/<state_id>/edit', EditCompensationStateView.as_view(), name='state-edit'),
|
path('<id>/state/<state_id>/edit', EditCompensationStateView.as_view(), name='state-edit'),
|
||||||
@ -43,7 +44,7 @@ urlpatterns = [
|
|||||||
path('<id>/deadline/new', NewCompensationDeadlineView.as_view(), name="new-deadline"),
|
path('<id>/deadline/new', NewCompensationDeadlineView.as_view(), name="new-deadline"),
|
||||||
path('<id>/deadline/<deadline_id>/edit', EditCompensationDeadlineView.as_view(), name='deadline-edit'),
|
path('<id>/deadline/<deadline_id>/edit', EditCompensationDeadlineView.as_view(), name='deadline-edit'),
|
||||||
path('<id>/deadline/<deadline_id>/remove', RemoveCompensationDeadlineView.as_view(), name='deadline-remove'),
|
path('<id>/deadline/<deadline_id>/remove', RemoveCompensationDeadlineView.as_view(), name='deadline-remove'),
|
||||||
path('<id>/report', report_view, name='report'),
|
path('<id>/report', CompensationReportView.as_view(), name='report'),
|
||||||
path('<id>/resub', CompensationResubmissionView.as_view(), name='resubmission-create'),
|
path('<id>/resub', CompensationResubmissionView.as_view(), name='resubmission-create'),
|
||||||
|
|
||||||
# Documents
|
# Documents
|
||||||
|
|||||||
@ -8,11 +8,11 @@ Created on: 24.08.21
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from compensation.autocomplete.eco_account import EcoAccountAutocomplete
|
from compensation.autocomplete.eco_account import EcoAccountAutocomplete
|
||||||
from compensation.views.eco_account.eco_account import index_view, new_view, new_id_view, edit_view, remove_view, \
|
from compensation.views.eco_account.eco_account import EcoAccountIndexView, EcoAccountIdentifierGeneratorView, \
|
||||||
detail_view
|
EcoAccountDetailView, NewEcoAccountFormView, EditEcoAccountFormView, RemoveEcoAccountView
|
||||||
from compensation.views.eco_account.log import EcoAccountLogView
|
from compensation.views.eco_account.log import EcoAccountLogView
|
||||||
from compensation.views.eco_account.record import EcoAccountRecordView
|
from compensation.views.eco_account.record import EcoAccountRecordView
|
||||||
from compensation.views.eco_account.report import report_view
|
from compensation.views.eco_account.report import EcoAccountReportView
|
||||||
from compensation.views.eco_account.resubmission import EcoAccountResubmissionView
|
from compensation.views.eco_account.resubmission import EcoAccountResubmissionView
|
||||||
from compensation.views.eco_account.state import NewEcoAccountStateView, EditEcoAccountStateView, \
|
from compensation.views.eco_account.state import NewEcoAccountStateView, EditEcoAccountStateView, \
|
||||||
RemoveEcoAccountStateView
|
RemoveEcoAccountStateView
|
||||||
@ -28,15 +28,15 @@ from compensation.views.eco_account.deduction import NewEcoAccountDeductionView,
|
|||||||
|
|
||||||
app_name = "acc"
|
app_name = "acc"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", index_view, name="index"),
|
path("", EcoAccountIndexView.as_view(), name="index"),
|
||||||
path('new/', new_view, name='new'),
|
path('new/', NewEcoAccountFormView.as_view(), name='new'),
|
||||||
path('new/id', new_id_view, name='new-id'),
|
path('new/id', EcoAccountIdentifierGeneratorView.as_view(), name='new-id'),
|
||||||
path('<id>', detail_view, name='detail'),
|
path('<id>', EcoAccountDetailView.as_view(), name='detail'),
|
||||||
path('<id>/log', EcoAccountLogView.as_view(), name='log'),
|
path('<id>/log', EcoAccountLogView.as_view(), name='log'),
|
||||||
path('<id>/record', EcoAccountRecordView.as_view(), name='record'),
|
path('<id>/record', EcoAccountRecordView.as_view(), name='record'),
|
||||||
path('<id>/report', report_view, name='report'),
|
path('<id>/report', EcoAccountReportView.as_view(), name='report'),
|
||||||
path('<id>/edit', edit_view, name='edit'),
|
path('<id>/edit', EditEcoAccountFormView.as_view(), name='edit'),
|
||||||
path('<id>/remove', remove_view, name='remove'),
|
path('<id>/remove', RemoveEcoAccountView.as_view(), name='remove'),
|
||||||
path('<id>/resub', EcoAccountResubmissionView.as_view(), name='resubmission-create'),
|
path('<id>/resub', EcoAccountResubmissionView.as_view(), name='resubmission-create'),
|
||||||
|
|
||||||
path('<id>/state/new', NewEcoAccountStateView.as_view(), name='new-state'),
|
path('<id>/state/new', NewEcoAccountStateView.as_view(), name='new-state'),
|
||||||
|
|||||||
@ -6,11 +6,11 @@ Created on: 24.08.21
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from compensation.views.payment import *
|
from compensation.views.payment import NewPaymentView, RemovePaymentView, EditPaymentView
|
||||||
|
|
||||||
app_name = "pay"
|
app_name = "pay"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('<id>/new', new_payment_view, name='new'),
|
path('<id>/new', NewPaymentView.as_view(), name='new'),
|
||||||
path('<id>/remove/<payment_id>', payment_remove_view, name='remove'),
|
path('<id>/remove/<payment_id>', RemovePaymentView.as_view(), name='remove'),
|
||||||
path('<id>/edit/<payment_id>', payment_edit_view, name='edit'),
|
path('<id>/edit/<payment_id>', EditPaymentView.as_view(), name='edit'),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -5,53 +5,23 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.http import HttpRequest
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.forms.modals.compensation_action import RemoveCompensationActionModalForm, \
|
from compensation.models import Compensation
|
||||||
EditCompensationActionModalForm, NewCompensationActionModalForm
|
|
||||||
from compensation.models import Compensation, CompensationAction
|
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.utils.message_templates import COMPENSATION_ACTION_REMOVED, COMPENSATION_ACTION_EDITED, \
|
|
||||||
COMPENSATION_ACTION_ADDED
|
|
||||||
from konova.views.action import AbstractNewCompensationActionView, AbstractEditCompensationActionView, \
|
from konova.views.action import AbstractNewCompensationActionView, AbstractEditCompensationActionView, \
|
||||||
AbstractRemoveCompensationActionView
|
AbstractRemoveCompensationActionView
|
||||||
|
|
||||||
|
_COMPENSATION_DETAIL_URL_NAME = "compensation:detail"
|
||||||
|
|
||||||
class NewCompensationActionView(AbstractNewCompensationActionView):
|
class NewCompensationActionView(AbstractNewCompensationActionView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
redirect_url = "compensation:detail"
|
_REDIRECT_URL = _COMPENSATION_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditCompensationActionView(AbstractEditCompensationActionView):
|
class EditCompensationActionView(AbstractEditCompensationActionView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
redirect_url = "compensation:detail"
|
_REDIRECT_URL = _COMPENSATION_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveCompensationActionView(AbstractRemoveCompensationActionView):
|
class RemoveCompensationActionView(AbstractRemoveCompensationActionView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
redirect_url = "compensation:detail"
|
_REDIRECT_URL = _COMPENSATION_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -7,8 +7,8 @@ Created on: 19.08.22
|
|||||||
"""
|
"""
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db.models import Sum
|
|
||||||
from django.http import HttpRequest, JsonResponse
|
from django.http import HttpRequest, JsonResponse
|
||||||
from django.shortcuts import get_object_or_404, render, redirect
|
from django.shortcuts import get_object_or_404, render, redirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@ -18,300 +18,157 @@ from compensation.forms.compensation import EditCompensationForm, NewCompensatio
|
|||||||
from compensation.models import Compensation
|
from compensation.models import Compensation
|
||||||
from compensation.tables.compensation import CompensationTable
|
from compensation.tables.compensation import CompensationTable
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.contexts import BaseContext
|
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
||||||
from konova.decorators import shared_access_required, default_group_required, any_group_check, login_required_modal, \
|
|
||||||
uuid_required
|
|
||||||
from konova.forms import SimpleGeomForm
|
|
||||||
from konova.forms.modals import RemoveModalForm
|
from konova.forms.modals import RemoveModalForm
|
||||||
from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP
|
|
||||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
|
||||||
from konova.utils.message_templates import COMPENSATION_REMOVED_TEMPLATE, DATA_CHECKED_PREVIOUSLY_TEMPLATE, \
|
from konova.utils.message_templates import COMPENSATION_REMOVED_TEMPLATE, DATA_CHECKED_PREVIOUSLY_TEMPLATE, \
|
||||||
RECORDED_BLOCKS_EDIT, CHECK_STATE_RESET, FORM_INVALID, PARAMS_INVALID, IDENTIFIER_REPLACED, \
|
RECORDED_BLOCKS_EDIT, PARAMS_INVALID
|
||||||
COMPENSATION_ADDED_TEMPLATE, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
|
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView, BaseNewSpatialLocatedObjectFormView, \
|
||||||
|
BaseEditSpatialLocatedObjectFormView
|
||||||
|
from konova.views.detail import BaseDetailView
|
||||||
|
from konova.views.remove import BaseRemoveModalFormView
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class CompensationIndexView(LoginRequiredMixin, BaseIndexView):
|
||||||
@any_group_check
|
_TAB_TITLE = _("Compensations - Overview")
|
||||||
def index_view(request: HttpRequest):
|
_INDEX_TABLE_CLS = CompensationTable
|
||||||
"""
|
|
||||||
Renders the index view for compensation
|
|
||||||
|
|
||||||
Args:
|
def _get_queryset(self):
|
||||||
request (HttpRequest): The incoming request
|
qs = Compensation.objects.filter(
|
||||||
|
deleted=None, # only show those which are not deleted individually
|
||||||
Returns:
|
intervention__deleted=None, # and don't show the ones whose intervention has been deleted
|
||||||
A rendered view
|
).order_by(
|
||||||
"""
|
"-modified__timestamp"
|
||||||
template = "generic_index.html"
|
)
|
||||||
compensations = Compensation.objects.filter(
|
return qs
|
||||||
deleted=None, # only show those which are not deleted individually
|
|
||||||
intervention__deleted=None, # and don't show the ones whose intervention has been deleted
|
|
||||||
).order_by(
|
|
||||||
"-modified__timestamp"
|
|
||||||
)
|
|
||||||
table = CompensationTable(
|
|
||||||
request=request,
|
|
||||||
queryset=compensations
|
|
||||||
)
|
|
||||||
context = {
|
|
||||||
"table": table,
|
|
||||||
TAB_TITLE_IDENTIFIER: _("Compensations - Overview"),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class NewCompensationFormView(BaseNewSpatialLocatedObjectFormView):
|
||||||
@default_group_required
|
_FORM_CLS = NewCompensationForm
|
||||||
@shared_access_required(Intervention, "intervention_id")
|
_MODEL_CLS = Compensation
|
||||||
def new_view(request: HttpRequest, intervention_id: str = None):
|
_TEMPLATE = "compensation/form/view.html"
|
||||||
"""
|
_TAB_TITLE = _("New Compensation")
|
||||||
Renders a view for a new compensation creation
|
_REDIRECT_URL = "compensation:detail"
|
||||||
|
|
||||||
Args:
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
request (HttpRequest): The incoming request
|
# On a new compensation make sure the intervention (if call came directly through an intervention's detail
|
||||||
|
# view) is shared with the user
|
||||||
|
intervention_id = kwargs.get("intervention_id", None)
|
||||||
|
if not intervention_id:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
intervention = get_object_or_404(Intervention, id=intervention_id)
|
||||||
|
return intervention.is_shared_with(user)
|
||||||
|
|
||||||
Returns:
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# User has to be an ets user
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
"""
|
def dispatch(self, request, *args, **kwargs):
|
||||||
template = "compensation/form/view.html"
|
# Make sure there is an existing intervention based on the given id
|
||||||
if intervention_id is not None:
|
# Compensations can not exist without an intervention
|
||||||
try:
|
intervention_id = kwargs.get("intervention_id", None)
|
||||||
intervention = Intervention.objects.get(id=intervention_id)
|
if intervention_id:
|
||||||
except ObjectDoesNotExist:
|
try:
|
||||||
messages.error(request, PARAMS_INVALID)
|
intervention = Intervention.objects.get(id=intervention_id)
|
||||||
return redirect("home")
|
if intervention.is_recorded:
|
||||||
if intervention.is_recorded:
|
messages.info(
|
||||||
messages.info(
|
request,
|
||||||
request,
|
RECORDED_BLOCKS_EDIT
|
||||||
RECORDED_BLOCKS_EDIT
|
|
||||||
)
|
|
||||||
return redirect("intervention:detail", id=intervention_id)
|
|
||||||
|
|
||||||
data_form = NewCompensationForm(request.POST or None, intervention_id=intervention_id)
|
|
||||||
geom_form = SimpleGeomForm(request.POST or None, read_only=False)
|
|
||||||
if request.method == "POST":
|
|
||||||
if data_form.is_valid() and geom_form.is_valid():
|
|
||||||
generated_identifier = data_form.cleaned_data.get("identifier", None)
|
|
||||||
comp = data_form.save(request.user, geom_form)
|
|
||||||
if generated_identifier != comp.identifier:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
IDENTIFIER_REPLACED.format(
|
|
||||||
generated_identifier,
|
|
||||||
comp.identifier
|
|
||||||
)
|
)
|
||||||
)
|
return redirect("intervention:detail", id=intervention_id)
|
||||||
messages.success(request, COMPENSATION_ADDED_TEMPLATE.format(comp.identifier))
|
except ObjectDoesNotExist:
|
||||||
if geom_form.has_geometry_simplified():
|
messages.error(request, PARAMS_INVALID, extra_tags="danger")
|
||||||
messages.info(
|
return redirect("home")
|
||||||
request,
|
return super().dispatch(request, *args, **kwargs)
|
||||||
GEOMETRY_SIMPLIFIED
|
|
||||||
)
|
|
||||||
|
|
||||||
num_ignored_geometries = geom_form.get_num_geometries_ignored()
|
|
||||||
if num_ignored_geometries > 0:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
GEOMETRIES_IGNORED_TEMPLATE.format(num_ignored_geometries)
|
|
||||||
)
|
|
||||||
|
|
||||||
return redirect("compensation:detail", id=comp.id)
|
|
||||||
else:
|
|
||||||
messages.error(request, FORM_INVALID, extra_tags="danger",)
|
|
||||||
else:
|
|
||||||
# For clarification: nothing in this case
|
|
||||||
pass
|
|
||||||
context = {
|
|
||||||
"form": data_form,
|
|
||||||
"geom_form": geom_form,
|
|
||||||
TAB_TITLE_IDENTIFIER: _("New compensation"),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class EditCompensationFormView(BaseEditSpatialLocatedObjectFormView):
|
||||||
@default_group_required
|
_MODEL_CLS = Compensation
|
||||||
def new_id_view(request: HttpRequest):
|
_FORM_CLS = EditCompensationForm
|
||||||
""" JSON endpoint
|
_TEMPLATE = "compensation/form/view.html"
|
||||||
|
_REDIRECT_URL = "compensation:detail"
|
||||||
|
|
||||||
Provides fetching of free identifiers for e.g. AJAX calls
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# User has to be a default user
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
"""
|
|
||||||
tmp = Compensation()
|
class CompensationIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
|
||||||
identifier = tmp.generate_new_identifier()
|
_MODEL_CLS = Compensation
|
||||||
while Compensation.objects.filter(identifier=identifier).exists():
|
_REDIRECT_URL = "compensation:index"
|
||||||
identifier = tmp.generate_new_identifier()
|
|
||||||
return JsonResponse(
|
|
||||||
data={
|
class CompensationDetailView(BaseDetailView):
|
||||||
"gen_data": identifier
|
_MODEL_CLS = Compensation
|
||||||
|
_TEMPLATE = "compensation/detail/compensation/view.html"
|
||||||
|
|
||||||
|
def _get_object(self, id: str):
|
||||||
|
""" Returns the compensation
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id (str): The compensation's id
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
obj (Compensation): The compensation
|
||||||
|
"""
|
||||||
|
comp = get_object_or_404(
|
||||||
|
Compensation.objects.select_related(
|
||||||
|
"modified",
|
||||||
|
"created",
|
||||||
|
"geometry"
|
||||||
|
),
|
||||||
|
id=id,
|
||||||
|
deleted=None,
|
||||||
|
intervention__deleted=None,
|
||||||
|
)
|
||||||
|
return comp
|
||||||
|
|
||||||
|
def _get_detail_context(self, obj: Compensation):
|
||||||
|
""" Generate object specific detail context for view
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (): The record
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Order states according to surface
|
||||||
|
before_states = obj.before_states.all().prefetch_related("biotope_type").order_by("-surface")
|
||||||
|
after_states = obj.after_states.all().prefetch_related("biotope_type").order_by("-surface")
|
||||||
|
actions = obj.actions.all().prefetch_related("action_type")
|
||||||
|
|
||||||
|
# Precalculate logical errors between before- and after-states
|
||||||
|
# Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling
|
||||||
|
sum_before_states = obj.get_surface_before_states()
|
||||||
|
sum_after_states = obj.get_surface_after_states()
|
||||||
|
diff_states = abs(sum_before_states - sum_after_states)
|
||||||
|
|
||||||
|
last_checked = obj.intervention.get_last_checked_action()
|
||||||
|
last_checked_tooltip = ""
|
||||||
|
if last_checked:
|
||||||
|
last_checked_tooltip = DATA_CHECKED_PREVIOUSLY_TEMPLATE.format(
|
||||||
|
last_checked.get_timestamp_str_formatted(),
|
||||||
|
last_checked.user
|
||||||
|
)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
"last_checked": last_checked,
|
||||||
|
"last_checked_tooltip": last_checked_tooltip,
|
||||||
|
"actions": actions,
|
||||||
|
"before_states": before_states,
|
||||||
|
"after_states": after_states,
|
||||||
|
"sum_before_states": sum_before_states,
|
||||||
|
"sum_after_states": sum_after_states,
|
||||||
|
"diff_states": diff_states,
|
||||||
|
"has_finished_deadlines": obj.get_finished_deadlines().exists(),
|
||||||
}
|
}
|
||||||
)
|
return context
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class RemoveCompensationView(LoginRequiredMixin, BaseRemoveModalFormView):
|
||||||
@default_group_required
|
_MODEL_CLS = Compensation
|
||||||
@shared_access_required(Compensation, "id")
|
_FORM_CLS = RemoveModalForm
|
||||||
def edit_view(request: HttpRequest, id: str):
|
_REDIRECT_URL = "compensation:index"
|
||||||
"""
|
|
||||||
Renders a view for editing compensations
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
template = "compensation/form/view.html"
|
|
||||||
# Get object from db
|
|
||||||
comp = get_object_or_404(Compensation, id=id)
|
|
||||||
if comp.is_recorded:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
RECORDED_BLOCKS_EDIT
|
|
||||||
)
|
|
||||||
return redirect("compensation:detail", id=id)
|
|
||||||
|
|
||||||
# Create forms, initialize with values from db/from POST request
|
|
||||||
data_form = EditCompensationForm(request.POST or None, instance=comp)
|
|
||||||
geom_form = SimpleGeomForm(request.POST or None, read_only=False, instance=comp)
|
|
||||||
if request.method == "POST":
|
|
||||||
if data_form.is_valid() and geom_form.is_valid():
|
|
||||||
# Preserve state of intervention checked to determine whether the user must be informed or not
|
|
||||||
# about a change of the check state
|
|
||||||
intervention_is_checked = comp.intervention.checked is not None
|
|
||||||
|
|
||||||
# The data form takes the geom form for processing, as well as the performing user
|
|
||||||
comp = data_form.save(request.user, geom_form)
|
|
||||||
if intervention_is_checked:
|
|
||||||
messages.info(request, CHECK_STATE_RESET)
|
|
||||||
messages.success(request, _("Compensation {} edited").format(comp.identifier))
|
|
||||||
if geom_form.has_geometry_simplified():
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
GEOMETRY_SIMPLIFIED
|
|
||||||
)
|
|
||||||
|
|
||||||
num_ignored_geometries = geom_form.get_num_geometries_ignored()
|
|
||||||
if num_ignored_geometries > 0:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
GEOMETRIES_IGNORED_TEMPLATE.format(num_ignored_geometries)
|
|
||||||
)
|
|
||||||
|
|
||||||
return redirect("compensation:detail", id=comp.id)
|
|
||||||
else:
|
|
||||||
messages.error(request, FORM_INVALID, extra_tags="danger",)
|
|
||||||
else:
|
|
||||||
# For clarification: nothing in this case
|
|
||||||
pass
|
|
||||||
context = {
|
|
||||||
"form": data_form,
|
|
||||||
"geom_form": geom_form,
|
|
||||||
TAB_TITLE_IDENTIFIER: _("Edit {}").format(comp.identifier),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@any_group_check
|
|
||||||
@uuid_required
|
|
||||||
def detail_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a detail view for a compensation
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The compensation's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
template = "compensation/detail/compensation/view.html"
|
|
||||||
comp = get_object_or_404(
|
|
||||||
Compensation.objects.select_related(
|
|
||||||
"modified",
|
|
||||||
"created",
|
|
||||||
"geometry"
|
|
||||||
),
|
|
||||||
id=id,
|
|
||||||
deleted=None,
|
|
||||||
intervention__deleted=None,
|
|
||||||
)
|
|
||||||
geom_form = SimpleGeomForm(instance=comp)
|
|
||||||
parcels = comp.get_underlying_parcels()
|
|
||||||
_user = request.user
|
|
||||||
is_data_shared = comp.intervention.is_shared_with(_user)
|
|
||||||
|
|
||||||
# Order states according to surface
|
|
||||||
before_states = comp.before_states.all().prefetch_related("biotope_type").order_by("-surface")
|
|
||||||
after_states = comp.after_states.all().prefetch_related("biotope_type").order_by("-surface")
|
|
||||||
actions = comp.actions.all().prefetch_related("action_type")
|
|
||||||
|
|
||||||
# Precalculate logical errors between before- and after-states
|
|
||||||
# Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling
|
|
||||||
sum_before_states = comp.get_surface_before_states()
|
|
||||||
sum_after_states = comp.get_surface_after_states()
|
|
||||||
diff_states = abs(sum_before_states - sum_after_states)
|
|
||||||
|
|
||||||
request = comp.set_status_messages(request)
|
|
||||||
|
|
||||||
last_checked = comp.intervention.get_last_checked_action()
|
|
||||||
last_checked_tooltip = ""
|
|
||||||
if last_checked:
|
|
||||||
last_checked_tooltip = DATA_CHECKED_PREVIOUSLY_TEMPLATE.format(last_checked.get_timestamp_str_formatted(), last_checked.user)
|
|
||||||
|
|
||||||
requesting_user_is_only_shared_user = comp.is_only_shared_with(_user)
|
|
||||||
if requesting_user_is_only_shared_user:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
DO_NOT_FORGET_TO_SHARE
|
|
||||||
)
|
|
||||||
|
|
||||||
context = {
|
|
||||||
"obj": comp,
|
|
||||||
"last_checked": last_checked,
|
|
||||||
"last_checked_tooltip": last_checked_tooltip,
|
|
||||||
"geom_form": geom_form,
|
|
||||||
"parcels": parcels,
|
|
||||||
"is_entry_shared": is_data_shared,
|
|
||||||
"actions": actions,
|
|
||||||
"before_states": before_states,
|
|
||||||
"after_states": after_states,
|
|
||||||
"sum_before_states": sum_before_states,
|
|
||||||
"sum_after_states": sum_after_states,
|
|
||||||
"diff_states": diff_states,
|
|
||||||
"is_default_member": _user.in_group(DEFAULT_GROUP),
|
|
||||||
"is_zb_member": _user.in_group(ZB_GROUP),
|
|
||||||
"is_ets_member": _user.in_group(ETS_GROUP),
|
|
||||||
"LANIS_LINK": comp.get_LANIS_link(),
|
|
||||||
TAB_TITLE_IDENTIFIER: f"{comp.identifier} - {comp.title}",
|
|
||||||
"has_finished_deadlines": comp.get_finished_deadlines().exists(),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required_modal
|
|
||||||
@login_required
|
|
||||||
@default_group_required
|
|
||||||
@shared_access_required(Compensation, "id")
|
|
||||||
def remove_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a modal view for removing the compensation
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The compensation's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
comp = get_object_or_404(Compensation, id=id)
|
|
||||||
form = RemoveModalForm(request.POST or None, instance=comp, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request=request,
|
|
||||||
msg_success=COMPENSATION_REMOVED_TEMPLATE.format(comp.identifier),
|
|
||||||
redirect_url=reverse("compensation:index"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_default_user()
|
||||||
|
|||||||
@ -5,45 +5,21 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import Compensation
|
from compensation.models import Compensation
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.views.deadline import AbstractRemoveDeadlineView, AbstractEditDeadlineView, AbstractNewDeadlineView
|
from konova.views.deadline import AbstractRemoveDeadlineView, AbstractEditDeadlineView, AbstractNewDeadlineView
|
||||||
|
|
||||||
|
_COMPENSATION_DETAIL_URL_NAME = "compensation:detail"
|
||||||
|
|
||||||
class NewCompensationDeadlineView(AbstractNewDeadlineView):
|
class NewCompensationDeadlineView(AbstractNewDeadlineView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
redirect_url = "compensation:detail"
|
_REDIRECT_URL = _COMPENSATION_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditCompensationDeadlineView(AbstractEditDeadlineView):
|
class EditCompensationDeadlineView(AbstractEditDeadlineView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
redirect_url = "compensation:detail"
|
_REDIRECT_URL = _COMPENSATION_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveCompensationDeadlineView(AbstractRemoveDeadlineView):
|
class RemoveCompensationDeadlineView(AbstractRemoveDeadlineView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
redirect_url = "compensation:detail"
|
_REDIRECT_URL = _COMPENSATION_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,62 +5,33 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from compensation.forms.modals.document import NewCompensationDocumentModalForm, EditCompensationDocumentModalForm, \
|
||||||
from django.utils.decorators import method_decorator
|
RemoveCompensationDocumentModalForm
|
||||||
|
|
||||||
from compensation.forms.modals.document import NewCompensationDocumentModalForm
|
|
||||||
from compensation.models import Compensation, CompensationDocument
|
from compensation.models import Compensation, CompensationDocument
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.forms.modals import EditDocumentModalForm
|
|
||||||
from konova.views.document import AbstractNewDocumentView, AbstractGetDocumentView, AbstractRemoveDocumentView, \
|
from konova.views.document import AbstractNewDocumentView, AbstractGetDocumentView, AbstractRemoveDocumentView, \
|
||||||
AbstractEditDocumentView
|
AbstractEditDocumentView
|
||||||
|
|
||||||
|
|
||||||
class NewCompensationDocumentView(AbstractNewDocumentView):
|
class NewCompensationDocumentView(AbstractNewDocumentView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
form = NewCompensationDocumentModalForm
|
_FORM_CLS = NewCompensationDocumentModalForm
|
||||||
redirect_url = "compensation:detail"
|
_REDIRECT_URL = "compensation:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class GetCompensationDocumentView(AbstractGetDocumentView):
|
class GetCompensationDocumentView(AbstractGetDocumentView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
document_model = CompensationDocument
|
_DOCUMENT_CLS = CompensationDocument
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveCompensationDocumentView(AbstractRemoveDocumentView):
|
class RemoveCompensationDocumentView(AbstractRemoveDocumentView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
document_model = CompensationDocument
|
_DOCUMENT_CLS = CompensationDocument
|
||||||
|
_FORM_CLS = RemoveCompensationDocumentModalForm
|
||||||
@method_decorator(login_required_modal)
|
_REDIRECT_URL = "compensation:detail"
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditCompensationDocumentView(AbstractEditDocumentView):
|
class EditCompensationDocumentView(AbstractEditDocumentView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
document_model = CompensationDocument
|
_DOCUMENT_CLS = CompensationDocument
|
||||||
form = EditDocumentModalForm
|
_FORM_CLS = EditCompensationDocumentModalForm
|
||||||
redirect_url = "compensation:detail"
|
_REDIRECT_URL = "compensation:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,20 +5,11 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import Compensation
|
from compensation.models import Compensation
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.views.log import AbstractLogView
|
from konova.views.log import AbstractLogView
|
||||||
|
|
||||||
|
|
||||||
class CompensationLogView(AbstractLogView):
|
class CompensationLogView(LoginRequiredMixin, AbstractLogView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,77 +5,48 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.http import HttpRequest
|
|
||||||
from django.shortcuts import get_object_or_404, render
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
from compensation.models import Compensation
|
from compensation.models import Compensation
|
||||||
from konova.contexts import BaseContext
|
from konova.sub_settings.django_settings import BASE_URL
|
||||||
from konova.decorators import uuid_required
|
from konova.utils.qrcode import QrCode
|
||||||
from konova.forms import SimpleGeomForm
|
from konova.views.report import BaseReportView
|
||||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
|
||||||
from konova.utils.generators import generate_qr_code
|
|
||||||
|
|
||||||
@uuid_required
|
|
||||||
def report_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders the public report view
|
|
||||||
|
|
||||||
Args:
|
class BaseCompensationReportView(BaseReportView):
|
||||||
request (HttpRequest): The incoming request
|
def _get_compensation_report_context(self, obj):
|
||||||
id (str): The id of the intervention
|
# Order states by surface
|
||||||
|
before_states = obj.before_states.all().order_by("-surface").prefetch_related("biotope_type")
|
||||||
|
after_states = obj.after_states.all().order_by("-surface").prefetch_related("biotope_type")
|
||||||
|
actions = obj.actions.all().prefetch_related("action_type")
|
||||||
|
|
||||||
Returns:
|
return {
|
||||||
|
"before_states": before_states,
|
||||||
"""
|
"after_states": after_states,
|
||||||
# Reuse the compensation report template since compensations are structurally identical
|
"actions": actions,
|
||||||
template = "compensation/report/compensation/report.html"
|
|
||||||
comp = get_object_or_404(Compensation, id=id)
|
|
||||||
|
|
||||||
tab_title = _("Report {}").format(comp.identifier)
|
|
||||||
# If intervention is not recorded (yet or currently) we need to render another template without any data
|
|
||||||
if not comp.is_ready_for_publish():
|
|
||||||
template = "report/unavailable.html"
|
|
||||||
context = {
|
|
||||||
TAB_TITLE_IDENTIFIER: tab_title,
|
|
||||||
}
|
}
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
# Prepare data for map viewer
|
|
||||||
geom_form = SimpleGeomForm(
|
|
||||||
instance=comp
|
|
||||||
)
|
|
||||||
parcels = comp.get_underlying_parcels()
|
|
||||||
|
|
||||||
qrcode_url = request.build_absolute_uri(reverse("compensation:report", args=(id,)))
|
class CompensationReportView(BaseCompensationReportView):
|
||||||
qrcode_img = generate_qr_code(qrcode_url, 10)
|
_MODEL = Compensation
|
||||||
qrcode_lanis_url = comp.get_LANIS_link()
|
_TEMPLATE = "compensation/report/compensation/report.html"
|
||||||
qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7)
|
|
||||||
|
|
||||||
# Order states by surface
|
def _get_report_context(self, obj):
|
||||||
before_states = comp.before_states.all().order_by("-surface").prefetch_related("biotope_type")
|
report_url = BASE_URL + reverse("compensation:report", args=(obj.id,))
|
||||||
after_states = comp.after_states.all().order_by("-surface").prefetch_related("biotope_type")
|
qrcode_report = QrCode(report_url, 10)
|
||||||
actions = comp.actions.all().prefetch_related("action_type")
|
qrcode_lanis = QrCode(obj.get_LANIS_link(), 7)
|
||||||
|
|
||||||
context = {
|
report_context = {
|
||||||
"obj": comp,
|
"qrcode": {
|
||||||
"qrcode": {
|
"img": qrcode_report.get_img(),
|
||||||
"img": qrcode_img,
|
"url": qrcode_report.get_content(),
|
||||||
"url": qrcode_url,
|
},
|
||||||
},
|
"qrcode_lanis": {
|
||||||
"qrcode_lanis": {
|
"img": qrcode_lanis.get_img(),
|
||||||
"img": qrcode_img_lanis,
|
"url": qrcode_lanis.get_content(),
|
||||||
"url": qrcode_lanis_url,
|
},
|
||||||
},
|
"is_entry_shared": False, # disables action buttons during rendering
|
||||||
"is_entry_shared": False, # disables action buttons during rendering
|
"tables_scrollable": False,
|
||||||
"before_states": before_states,
|
}
|
||||||
"after_states": after_states,
|
report_context.update(self._get_compensation_report_context(obj))
|
||||||
"geom_form": geom_form,
|
return report_context
|
||||||
"parcels": parcels,
|
|
||||||
"actions": actions,
|
|
||||||
"tables_scrollable": False,
|
|
||||||
TAB_TITLE_IDENTIFIER: tab_title,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
@ -5,22 +5,12 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from compensation.forms.modals.resubmission import CompensationResubmissionModalForm
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import Compensation
|
from compensation.models import Compensation
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.views.resubmission import AbstractResubmissionView
|
from konova.views.resubmission import AbstractResubmissionView
|
||||||
|
|
||||||
|
|
||||||
class CompensationResubmissionView(AbstractResubmissionView):
|
class CompensationResubmissionView(AbstractResubmissionView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
redirect_url_base = "compensation:detail"
|
_FORM_CLS = CompensationResubmissionModalForm
|
||||||
form_action_url_base = "compensation:resubmission-create"
|
_REDIRECT_URL = "compensation:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,46 +5,21 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import Compensation
|
from compensation.models import Compensation
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.views.state import AbstractNewCompensationStateView, AbstractEditCompensationStateView, \
|
from konova.views.state import AbstractNewCompensationStateView, AbstractEditCompensationStateView, \
|
||||||
AbstractRemoveCompensationStateView
|
AbstractRemoveCompensationStateView
|
||||||
|
|
||||||
|
|
||||||
class NewCompensationStateView(AbstractNewCompensationStateView):
|
class NewCompensationStateView(AbstractNewCompensationStateView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
redirect_url = "compensation:detail"
|
_REDIRECT_URL = "compensation:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditCompensationStateView(AbstractEditCompensationStateView):
|
class EditCompensationStateView(AbstractEditCompensationStateView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
redirect_url = "compensation:detail"
|
_REDIRECT_URL = "compensation:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveCompensationStateView(AbstractRemoveCompensationStateView):
|
class RemoveCompensationStateView(AbstractRemoveCompensationStateView):
|
||||||
model = Compensation
|
_MODEL_CLS = Compensation
|
||||||
redirect_url = "compensation:detail"
|
_REDIRECT_URL = "compensation:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Compensation, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,46 +5,22 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import EcoAccount
|
from compensation.models import EcoAccount
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.views.action import AbstractNewCompensationActionView, AbstractEditCompensationActionView, \
|
from konova.views.action import AbstractNewCompensationActionView, AbstractEditCompensationActionView, \
|
||||||
AbstractRemoveCompensationActionView
|
AbstractRemoveCompensationActionView
|
||||||
|
|
||||||
|
_ECO_ACCOUNT_DETAIL_URL_NAME = "compensation:acc:detail"
|
||||||
|
|
||||||
class NewEcoAccountActionView(AbstractNewCompensationActionView):
|
class NewEcoAccountActionView(AbstractNewCompensationActionView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = _ECO_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditEcoAccountActionView(AbstractEditCompensationActionView):
|
class EditEcoAccountActionView(AbstractEditCompensationActionView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = _ECO_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveEcoAccountActionView(AbstractRemoveCompensationActionView):
|
class RemoveEcoAccountActionView(AbstractRemoveCompensationActionView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = _ECO_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,45 +5,22 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import EcoAccount
|
from compensation.models import EcoAccount
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.views.deadline import AbstractNewDeadlineView, AbstractEditDeadlineView, AbstractRemoveDeadlineView
|
from konova.views.deadline import AbstractNewDeadlineView, AbstractEditDeadlineView, AbstractRemoveDeadlineView
|
||||||
|
|
||||||
|
_ECO_ACCOUNT_DETAIL_URL_NAME = "compensation:acc:detail"
|
||||||
|
|
||||||
class NewEcoAccountDeadlineView(AbstractNewDeadlineView):
|
class NewEcoAccountDeadlineView(AbstractNewDeadlineView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = _ECO_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditEcoAccountDeadlineView(AbstractEditDeadlineView):
|
class EditEcoAccountDeadlineView(AbstractEditDeadlineView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = _ECO_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveEcoAccountDeadlineView(AbstractRemoveDeadlineView):
|
class RemoveEcoAccountDeadlineView(AbstractRemoveDeadlineView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = _ECO_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,54 +5,33 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import EcoAccount
|
from compensation.models import EcoAccount
|
||||||
from konova.decorators import default_group_required, login_required_modal
|
|
||||||
from konova.views.deduction import AbstractNewDeductionView, AbstractEditDeductionView, AbstractRemoveDeductionView
|
from konova.views.deduction import AbstractNewDeductionView, AbstractEditDeductionView, AbstractRemoveDeductionView
|
||||||
|
|
||||||
|
_ECO_ACCOUNT_DETAIl_URL_NAME = "compensation:acc:detail"
|
||||||
|
|
||||||
class NewEcoAccountDeductionView(AbstractNewDeductionView):
|
class NewEcoAccountDeductionView(LoginRequiredMixin, AbstractNewDeductionView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = _ECO_ACCOUNT_DETAIl_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def _custom_check(self, obj):
|
def _custom_check(self, obj):
|
||||||
|
# New deductions can only be created if the eco account has been recorded
|
||||||
if not obj.recorded:
|
if not obj.recorded:
|
||||||
raise Http404()
|
raise Http404()
|
||||||
|
|
||||||
|
def _check_for_recorded_instance(self, obj):
|
||||||
class EditEcoAccountDeductionView(AbstractEditDeductionView):
|
# Deductions can be created on recorded as well as on non-recorded entries
|
||||||
def _custom_check(self, obj):
|
return None
|
||||||
pass
|
|
||||||
|
|
||||||
model = EcoAccount
|
|
||||||
redirect_url = "compensation:acc:detail"
|
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveEcoAccountDeductionView(AbstractRemoveDeductionView):
|
class EditEcoAccountDeductionView(LoginRequiredMixin, AbstractEditDeductionView):
|
||||||
def _custom_check(self, obj):
|
_MODEL_CLS = EcoAccount
|
||||||
pass
|
_REDIRECT_URL = _ECO_ACCOUNT_DETAIl_URL_NAME
|
||||||
|
|
||||||
model = EcoAccount
|
|
||||||
redirect_url = "compensation:acc:detail"
|
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
class RemoveEcoAccountDeductionView(LoginRequiredMixin, AbstractRemoveDeductionView):
|
||||||
|
_MODEL_CLS = EcoAccount
|
||||||
|
_REDIRECT_URL = _ECO_ACCOUNT_DETAIl_URL_NAME
|
||||||
|
|||||||
@ -5,65 +5,33 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from compensation.forms.modals.document import NewEcoAccountDocumentModalForm, RemoveEcoAccountDocumentModalForm, \
|
||||||
from django.http import HttpRequest
|
EditEcoAccountDocumentModalForm
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.forms.modals.document import NewEcoAccountDocumentModalForm
|
|
||||||
from compensation.models import EcoAccount, EcoAccountDocument
|
from compensation.models import EcoAccount, EcoAccountDocument
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.forms.modals import EditDocumentModalForm
|
|
||||||
from konova.views.document import AbstractNewDocumentView, AbstractGetDocumentView, AbstractRemoveDocumentView, \
|
from konova.views.document import AbstractNewDocumentView, AbstractGetDocumentView, AbstractRemoveDocumentView, \
|
||||||
AbstractEditDocumentView
|
AbstractEditDocumentView
|
||||||
|
|
||||||
|
|
||||||
class NewEcoAccountDocumentView(AbstractNewDocumentView):
|
class NewEcoAccountDocumentView(AbstractNewDocumentView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
form = NewEcoAccountDocumentModalForm
|
_FORM_CLS = NewEcoAccountDocumentModalForm
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class GetEcoAccountDocumentView(AbstractGetDocumentView):
|
class GetEcoAccountDocumentView(AbstractGetDocumentView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
document_model = EcoAccountDocument
|
_DOCUMENT_CLS = EcoAccountDocument
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveEcoAccountDocumentView(AbstractRemoveDocumentView):
|
class RemoveEcoAccountDocumentView(AbstractRemoveDocumentView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
document_model = EcoAccountDocument
|
_DOCUMENT_CLS = EcoAccountDocument
|
||||||
|
_FORM_CLS = RemoveEcoAccountDocumentModalForm
|
||||||
@method_decorator(login_required_modal)
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditEcoAccountDocumentView(AbstractEditDocumentView):
|
class EditEcoAccountDocumentView(AbstractEditDocumentView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
document_model = EcoAccountDocument
|
_DOCUMENT_CLS = EcoAccountDocument
|
||||||
form = EditDocumentModalForm
|
_FORM_CLS = EditEcoAccountDocumentModalForm
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -7,8 +7,8 @@ Created on: 19.08.22
|
|||||||
"""
|
"""
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.db.models import Sum
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.http import HttpRequest, JsonResponse
|
from django.http import HttpRequest
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@ -17,43 +17,52 @@ from compensation.forms.eco_account import EditEcoAccountForm, NewEcoAccountForm
|
|||||||
from compensation.models import EcoAccount
|
from compensation.models import EcoAccount
|
||||||
from compensation.tables.eco_account import EcoAccountTable
|
from compensation.tables.eco_account import EcoAccountTable
|
||||||
from konova.contexts import BaseContext
|
from konova.contexts import BaseContext
|
||||||
from konova.decorators import shared_access_required, default_group_required, any_group_check, login_required_modal, \
|
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
||||||
uuid_required
|
|
||||||
from konova.forms import SimpleGeomForm
|
from konova.forms import SimpleGeomForm
|
||||||
from konova.settings import ETS_GROUP, DEFAULT_GROUP, ZB_GROUP
|
from konova.settings import ETS_GROUP
|
||||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
||||||
from konova.utils.message_templates import CANCEL_ACC_RECORDED_OR_DEDUCTED, RECORDED_BLOCKS_EDIT, FORM_INVALID, \
|
from konova.utils.message_templates import CANCEL_ACC_RECORDED_OR_DEDUCTED, RECORDED_BLOCKS_EDIT, FORM_INVALID, \
|
||||||
IDENTIFIER_REPLACED, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
|
IDENTIFIER_REPLACED, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
|
||||||
|
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView, BaseNewSpatialLocatedObjectFormView, \
|
||||||
|
BaseEditSpatialLocatedObjectFormView
|
||||||
|
from konova.views.detail import BaseDetailView
|
||||||
|
from konova.views.remove import BaseRemoveModalFormView
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class EcoAccountIndexView(LoginRequiredMixin, BaseIndexView):
|
||||||
@any_group_check
|
_INDEX_TABLE_CLS = EcoAccountTable
|
||||||
def index_view(request: HttpRequest):
|
_TAB_TITLE = _("Eco-account - Overview")
|
||||||
"""
|
|
||||||
Renders the index view for eco accounts
|
|
||||||
|
|
||||||
Args:
|
def _get_queryset(self):
|
||||||
request (HttpRequest): The incoming request
|
qs = EcoAccount.objects.filter(
|
||||||
|
deleted=None,
|
||||||
|
).order_by(
|
||||||
|
"-modified__timestamp"
|
||||||
|
)
|
||||||
|
return qs
|
||||||
|
|
||||||
Returns:
|
|
||||||
A rendered view
|
class NewEcoAccountFormView(BaseNewSpatialLocatedObjectFormView):
|
||||||
"""
|
_FORM_CLS = NewEcoAccountForm
|
||||||
template = "generic_index.html"
|
_MODEL_CLS = EcoAccount
|
||||||
eco_accounts = EcoAccount.objects.filter(
|
_TEMPLATE = "compensation/form/view.html"
|
||||||
deleted=None,
|
_TAB_TITLE = _("New Eco-Account")
|
||||||
).order_by(
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
"-modified__timestamp"
|
|
||||||
)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
table = EcoAccountTable(
|
# User has to be a default user
|
||||||
request=request,
|
return user.is_default_user()
|
||||||
queryset=eco_accounts
|
|
||||||
)
|
|
||||||
context = {
|
class EditEcoAccountFormView(BaseEditSpatialLocatedObjectFormView):
|
||||||
"table": table,
|
_FORM_CLS = EditEcoAccountForm
|
||||||
TAB_TITLE_IDENTIFIER: _("Eco-account - Overview"),
|
_MODEL_CLS = EcoAccount
|
||||||
}
|
_TEMPLATE = "compensation/form/view.html"
|
||||||
context = BaseContext(request, context).context
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
return render(request, template, context)
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# User has to be a default user
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -112,23 +121,9 @@ def new_view(request: HttpRequest):
|
|||||||
return render(request, template, context)
|
return render(request, template, context)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class EcoAccountIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
|
||||||
@default_group_required
|
_MODEL_CLS = EcoAccount
|
||||||
def new_id_view(request: HttpRequest):
|
_REDIRECT_URL = "compensation:acc:index"
|
||||||
""" JSON endpoint
|
|
||||||
|
|
||||||
Provides fetching of free identifiers for e.g. AJAX calls
|
|
||||||
|
|
||||||
"""
|
|
||||||
tmp = EcoAccount()
|
|
||||||
identifier = tmp.generate_new_identifier()
|
|
||||||
while EcoAccount.objects.filter(identifier=identifier).exists():
|
|
||||||
identifier = tmp.generate_new_identifier()
|
|
||||||
return JsonResponse(
|
|
||||||
data={
|
|
||||||
"gen_data": identifier
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -192,116 +187,78 @@ def edit_view(request: HttpRequest, id: str):
|
|||||||
return render(request, template, context)
|
return render(request, template, context)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class EcoAccountDetailView(BaseDetailView):
|
||||||
@any_group_check
|
_MODEL_CLS = EcoAccount
|
||||||
@uuid_required
|
_TEMPLATE = "compensation/detail/eco_account/view.html"
|
||||||
def detail_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a detail view for a compensation
|
|
||||||
|
|
||||||
Args:
|
def _get_object(self, id: str):
|
||||||
request (HttpRequest): The incoming request
|
""" Fetch object for detail view
|
||||||
id (str): The compensation's id
|
|
||||||
|
|
||||||
Returns:
|
Args:
|
||||||
|
id (str): The record's id'
|
||||||
|
|
||||||
"""
|
Returns:
|
||||||
template = "compensation/detail/eco_account/view.html"
|
|
||||||
acc = get_object_or_404(
|
|
||||||
EcoAccount.objects.prefetch_related(
|
|
||||||
"deadlines",
|
|
||||||
).select_related(
|
|
||||||
'geometry',
|
|
||||||
'responsible',
|
|
||||||
),
|
|
||||||
id=id,
|
|
||||||
deleted=None,
|
|
||||||
)
|
|
||||||
geom_form = SimpleGeomForm(instance=acc)
|
|
||||||
parcels = acc.get_underlying_parcels()
|
|
||||||
_user = request.user
|
|
||||||
is_data_shared = acc.is_shared_with(_user)
|
|
||||||
|
|
||||||
# Order states according to surface
|
"""
|
||||||
before_states = acc.before_states.order_by("-surface")
|
acc = get_object_or_404(
|
||||||
after_states = acc.after_states.order_by("-surface")
|
EcoAccount.objects.prefetch_related(
|
||||||
|
"deadlines",
|
||||||
# Precalculate logical errors between before- and after-states
|
).select_related(
|
||||||
# Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling
|
'geometry',
|
||||||
sum_before_states = acc.get_surface_before_states()
|
'responsible',
|
||||||
sum_after_states = acc.get_surface_after_states()
|
),
|
||||||
diff_states = abs(sum_before_states - sum_after_states)
|
id=id,
|
||||||
# Calculate rest of available surface for deductions
|
deleted=None,
|
||||||
available_total = acc.deductable_rest
|
|
||||||
available_relative = acc.get_deductable_rest_relative()
|
|
||||||
|
|
||||||
# Prefetch related data to decrease the amount of db connections
|
|
||||||
deductions = acc.deductions.filter(
|
|
||||||
intervention__deleted=None,
|
|
||||||
)
|
|
||||||
actions = acc.actions.all()
|
|
||||||
|
|
||||||
request = acc.set_status_messages(request)
|
|
||||||
|
|
||||||
requesting_user_is_only_shared_user = acc.is_only_shared_with(_user)
|
|
||||||
if requesting_user_is_only_shared_user:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
DO_NOT_FORGET_TO_SHARE
|
|
||||||
)
|
)
|
||||||
|
return acc
|
||||||
|
|
||||||
context = {
|
def _get_detail_context(self, obj: EcoAccount):
|
||||||
"obj": acc,
|
""" Generate object specific detail context for view
|
||||||
"geom_form": geom_form,
|
|
||||||
"parcels": parcels,
|
Args:
|
||||||
"is_entry_shared": is_data_shared,
|
obj (): The record
|
||||||
"before_states": before_states,
|
|
||||||
"after_states": after_states,
|
Returns:
|
||||||
"sum_before_states": sum_before_states,
|
|
||||||
"sum_after_states": sum_after_states,
|
"""
|
||||||
"diff_states": diff_states,
|
# Order states according to surface
|
||||||
"available": available_relative,
|
before_states = obj.before_states.order_by("-surface")
|
||||||
"available_total": available_total,
|
after_states = obj.after_states.order_by("-surface")
|
||||||
"is_default_member": _user.in_group(DEFAULT_GROUP),
|
|
||||||
"is_zb_member": _user.in_group(ZB_GROUP),
|
# Precalculate logical errors between before- and after-states
|
||||||
"is_ets_member": _user.in_group(ETS_GROUP),
|
# Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling
|
||||||
"LANIS_LINK": acc.get_LANIS_link(),
|
sum_before_states = obj.get_surface_before_states()
|
||||||
"deductions": deductions,
|
sum_after_states = obj.get_surface_after_states()
|
||||||
"actions": actions,
|
diff_states = abs(sum_before_states - sum_after_states)
|
||||||
TAB_TITLE_IDENTIFIER: f"{acc.identifier} - {acc.title}",
|
# Calculate rest of available surface for deductions
|
||||||
"has_finished_deadlines": acc.get_finished_deadlines().exists(),
|
available_total = obj.deductable_rest
|
||||||
}
|
available_relative = obj.get_deductable_rest_relative()
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
# Prefetch related data to decrease the amount of db connections
|
||||||
|
deductions = obj.deductions.filter(
|
||||||
|
intervention__deleted=None,
|
||||||
|
)
|
||||||
|
actions = obj.actions.all()
|
||||||
|
|
||||||
|
context = {
|
||||||
|
"before_states": before_states,
|
||||||
|
"after_states": after_states,
|
||||||
|
"sum_before_states": sum_before_states,
|
||||||
|
"sum_after_states": sum_after_states,
|
||||||
|
"diff_states": diff_states,
|
||||||
|
"available": available_relative,
|
||||||
|
"available_total": available_total,
|
||||||
|
"deductions": deductions,
|
||||||
|
"actions": actions,
|
||||||
|
"has_finished_deadlines": obj.get_finished_deadlines().exists(),
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
@login_required_modal
|
class RemoveEcoAccountView(LoginRequiredMixin, BaseRemoveModalFormView):
|
||||||
@login_required
|
_MODEL_CLS = EcoAccount
|
||||||
@default_group_required
|
_FORM_CLS = RemoveEcoAccountModalForm
|
||||||
@shared_access_required(EcoAccount, "id")
|
_REDIRECT_URL = "compensation:acc:index"
|
||||||
def remove_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a modal view for removing the eco account
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The account's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
acc = get_object_or_404(EcoAccount, id=id)
|
|
||||||
|
|
||||||
# If the eco account has already been recorded OR there are already deductions, it can not be deleted by a regular
|
|
||||||
# default group user
|
|
||||||
if acc.recorded is not None or acc.deductions.exists():
|
|
||||||
user = request.user
|
|
||||||
if not user.in_group(ETS_GROUP):
|
|
||||||
messages.info(request, CANCEL_ACC_RECORDED_OR_DEDUCTED)
|
|
||||||
return redirect("compensation:acc:detail", id=id)
|
|
||||||
|
|
||||||
form = RemoveEcoAccountModalForm(request.POST or None, instance=acc, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request=request,
|
|
||||||
msg_success=_("Eco-account removed"),
|
|
||||||
redirect_url=reverse("compensation:acc:index"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_default_user()
|
||||||
|
|||||||
@ -5,20 +5,11 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import EcoAccount
|
from compensation.models import EcoAccount
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.views.log import AbstractLogView
|
from konova.views.log import AbstractLogView
|
||||||
|
|
||||||
|
|
||||||
class EcoAccountLogView(AbstractLogView):
|
class EcoAccountLogView(LoginRequiredMixin, AbstractLogView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,20 +5,12 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import EcoAccount
|
from compensation.models import EcoAccount
|
||||||
from konova.decorators import shared_access_required, conservation_office_group_required, login_required_modal
|
|
||||||
from konova.views.record import AbstractRecordView
|
from konova.views.record import AbstractRecordView
|
||||||
|
|
||||||
|
|
||||||
class EcoAccountRecordView(AbstractRecordView):
|
class EcoAccountRecordView(LoginRequiredMixin, AbstractRecordView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,85 +5,41 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.http import HttpRequest
|
|
||||||
from django.shortcuts import get_object_or_404, render
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
from compensation.models import EcoAccount
|
from compensation.models import EcoAccount
|
||||||
from konova.contexts import BaseContext
|
from compensation.views.compensation.report import BaseCompensationReportView
|
||||||
from konova.decorators import uuid_required
|
from konova.sub_settings.django_settings import BASE_URL
|
||||||
from konova.forms import SimpleGeomForm
|
from konova.utils.qrcode import QrCode
|
||||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
|
||||||
from konova.utils.generators import generate_qr_code
|
|
||||||
|
|
||||||
|
|
||||||
@uuid_required
|
class EcoAccountReportView(BaseCompensationReportView):
|
||||||
def report_view(request: HttpRequest, id: str):
|
_MODEL = EcoAccount
|
||||||
""" Renders the public report view
|
_TEMPLATE = "compensation/report/eco_account/report.html"
|
||||||
|
|
||||||
Args:
|
def _get_report_context(self, obj):
|
||||||
request (HttpRequest): The incoming request
|
report_url = BASE_URL + reverse("compensation:acc:report", args=(obj.id,))
|
||||||
id (str): The id of the intervention
|
qrcode_report = QrCode(report_url, 10)
|
||||||
|
qrcode_lanis = QrCode(obj.get_LANIS_link(), 7)
|
||||||
|
|
||||||
Returns:
|
# Reduce amount of db fetched data to the bare minimum we need in the template (deduction's intervention id and identifier)
|
||||||
|
deductions = obj.deductions.all() \
|
||||||
|
.distinct("intervention") \
|
||||||
|
.select_related("intervention") \
|
||||||
|
.values_list("intervention__id", "intervention__identifier", "intervention__title", named=True)
|
||||||
|
|
||||||
"""
|
report_context = {
|
||||||
# Reuse the compensation report template since EcoAccounts are structurally identical
|
"qrcode": {
|
||||||
template = "compensation/report/eco_account/report.html"
|
"img": qrcode_report.get_img(),
|
||||||
acc = get_object_or_404(EcoAccount, id=id)
|
"url": qrcode_report.get_content(),
|
||||||
|
},
|
||||||
tab_title = _("Report {}").format(acc.identifier)
|
"qrcode_lanis": {
|
||||||
# If intervention is not recorded (yet or currently) we need to render another template without any data
|
"img": qrcode_lanis.get_img(),
|
||||||
if not acc.is_ready_for_publish():
|
"url": qrcode_lanis.get_content(),
|
||||||
template = "report/unavailable.html"
|
},
|
||||||
context = {
|
"is_entry_shared": False, # disables action buttons during rendering
|
||||||
TAB_TITLE_IDENTIFIER: tab_title,
|
"deductions": deductions,
|
||||||
|
"tables_scrollable": False,
|
||||||
}
|
}
|
||||||
context = BaseContext(request, context).context
|
report_context.update(self._get_compensation_report_context(obj))
|
||||||
return render(request, template, context)
|
return report_context
|
||||||
|
|
||||||
# Prepare data for map viewer
|
|
||||||
geom_form = SimpleGeomForm(
|
|
||||||
instance=acc
|
|
||||||
)
|
|
||||||
parcels = acc.get_underlying_parcels()
|
|
||||||
|
|
||||||
qrcode_url = request.build_absolute_uri(reverse("compensation:acc:report", args=(id,)))
|
|
||||||
qrcode_img = generate_qr_code(qrcode_url, 10)
|
|
||||||
qrcode_lanis_url = acc.get_LANIS_link()
|
|
||||||
qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7)
|
|
||||||
|
|
||||||
# Order states by surface
|
|
||||||
before_states = acc.before_states.all().order_by("-surface").select_related("biotope_type__parent")
|
|
||||||
after_states = acc.after_states.all().order_by("-surface").select_related("biotope_type__parent")
|
|
||||||
actions = acc.actions.all().prefetch_related("action_type__parent")
|
|
||||||
|
|
||||||
# Reduce amount of db fetched data to the bare minimum we need in the template (deduction's intervention id and identifier)
|
|
||||||
deductions = acc.deductions.all()\
|
|
||||||
.distinct("intervention")\
|
|
||||||
.select_related("intervention")\
|
|
||||||
.values_list("intervention__id", "intervention__identifier", "intervention__title", named=True)
|
|
||||||
|
|
||||||
context = {
|
|
||||||
"obj": acc,
|
|
||||||
"qrcode": {
|
|
||||||
"img": qrcode_img,
|
|
||||||
"url": qrcode_url,
|
|
||||||
},
|
|
||||||
"qrcode_lanis": {
|
|
||||||
"img": qrcode_img_lanis,
|
|
||||||
"url": qrcode_lanis_url,
|
|
||||||
},
|
|
||||||
"is_entry_shared": False, # disables action buttons during rendering
|
|
||||||
"before_states": before_states,
|
|
||||||
"after_states": after_states,
|
|
||||||
"geom_form": geom_form,
|
|
||||||
"parcels": parcels,
|
|
||||||
"actions": actions,
|
|
||||||
"deductions": deductions,
|
|
||||||
"tables_scrollable": False,
|
|
||||||
TAB_TITLE_IDENTIFIER: tab_title,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|||||||
@ -5,22 +5,12 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from compensation.forms.modals.resubmission import EcoAccountResubmissionModalForm
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import EcoAccount
|
from compensation.models import EcoAccount
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.views.resubmission import AbstractResubmissionView
|
from konova.views.resubmission import AbstractResubmissionView
|
||||||
|
|
||||||
|
|
||||||
class EcoAccountResubmissionView(AbstractResubmissionView):
|
class EcoAccountResubmissionView(AbstractResubmissionView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url_base = "compensation:acc:detail"
|
_FORM_CLS = EcoAccountResubmissionModalForm
|
||||||
form_action_url_base = "compensation:acc:resubmission-create"
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,29 +5,15 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import EcoAccount
|
from compensation.models import EcoAccount
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.views.share import AbstractShareByTokenView, AbstractShareFormView
|
from konova.views.share import AbstractShareByTokenView, AbstractShareFormView
|
||||||
|
|
||||||
|
|
||||||
class EcoAccountShareByTokenView(AbstractShareByTokenView):
|
class EcoAccountShareByTokenView(AbstractShareByTokenView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EcoAccountShareFormView(AbstractShareFormView):
|
class EcoAccountShareFormView(AbstractShareFormView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,46 +5,21 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from compensation.models import EcoAccount
|
from compensation.models import EcoAccount
|
||||||
from konova.decorators import shared_access_required, default_group_required, login_required_modal
|
|
||||||
from konova.views.state import AbstractNewCompensationStateView, AbstractEditCompensationStateView, \
|
from konova.views.state import AbstractNewCompensationStateView, AbstractEditCompensationStateView, \
|
||||||
AbstractRemoveCompensationStateView
|
AbstractRemoveCompensationStateView
|
||||||
|
|
||||||
|
|
||||||
class NewEcoAccountStateView(AbstractNewCompensationStateView):
|
class NewEcoAccountStateView(AbstractNewCompensationStateView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditEcoAccountStateView(AbstractEditCompensationStateView):
|
class EditEcoAccountStateView(AbstractEditCompensationStateView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveEcoAccountStateView(AbstractRemoveCompensationStateView):
|
class RemoveEcoAccountStateView(AbstractRemoveCompensationStateView):
|
||||||
model = EcoAccount
|
_MODEL_CLS = EcoAccount
|
||||||
redirect_url = "compensation:acc:detail"
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(EcoAccount, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,84 +5,38 @@ Contact: michel.peltriaux@sgdnord.rlp.de
|
|||||||
Created on: 09.08.21
|
Created on: 09.08.21
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.urls import reverse
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.http import HttpRequest
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
|
|
||||||
from compensation.forms.modals.payment import NewPaymentForm, RemovePaymentModalForm, EditPaymentModalForm
|
from compensation.forms.modals.payment import NewPaymentForm, RemovePaymentModalForm, EditPaymentModalForm
|
||||||
from compensation.models import Payment
|
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.decorators import default_group_required, shared_access_required
|
|
||||||
from konova.utils.message_templates import PAYMENT_ADDED, PAYMENT_REMOVED, PAYMENT_EDITED
|
from konova.utils.message_templates import PAYMENT_ADDED, PAYMENT_REMOVED, PAYMENT_EDITED
|
||||||
|
from konova.views.base import BaseModalFormView
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class BasePaymentView(LoginRequiredMixin, BaseModalFormView):
|
||||||
@default_group_required
|
_MODEL_CLS = Intervention
|
||||||
@shared_access_required(Intervention, "id")
|
_REDIRECT_URL = "intervention:detail"
|
||||||
def new_payment_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a modal view for adding new payments
|
|
||||||
|
|
||||||
Args:
|
class Meta:
|
||||||
request (HttpRequest): The incoming request
|
abstract = True
|
||||||
id (str): The intervention's id for which a new payment shall be added
|
|
||||||
|
|
||||||
Returns:
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
url = super()._get_redirect_url(*args, **kwargs)
|
||||||
|
return f"{url}#related_data"
|
||||||
|
|
||||||
"""
|
def _user_has_permission(self, user, **kwargs):
|
||||||
intervention = get_object_or_404(Intervention, id=id)
|
return user.is_default_user()
|
||||||
form = NewPaymentForm(request.POST or None, instance=intervention, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=PAYMENT_ADDED,
|
|
||||||
redirect_url=reverse("intervention:detail", args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class NewPaymentView(BasePaymentView):
|
||||||
@default_group_required
|
_FORM_CLS = NewPaymentForm
|
||||||
@shared_access_required(Intervention, "id")
|
_MSG_SUCCESS = PAYMENT_ADDED
|
||||||
def payment_remove_view(request: HttpRequest, id: str, payment_id: str):
|
|
||||||
""" Renders a modal view for removing payments
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The intervention's id
|
|
||||||
payment_id (str): The payment's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
intervention = get_object_or_404(Intervention, id=id)
|
|
||||||
payment = get_object_or_404(Payment, id=payment_id)
|
|
||||||
form = RemovePaymentModalForm(request.POST or None, instance=intervention, payment=payment, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request=request,
|
|
||||||
msg_success=PAYMENT_REMOVED,
|
|
||||||
redirect_url=reverse("intervention:detail", args=(payment.intervention_id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class EditPaymentView(BasePaymentView):
|
||||||
@default_group_required
|
_MSG_SUCCESS = PAYMENT_EDITED
|
||||||
@shared_access_required(Intervention, "id")
|
_FORM_CLS = EditPaymentModalForm
|
||||||
def payment_edit_view(request: HttpRequest, id: str, payment_id: str):
|
|
||||||
""" Renders a modal view for editing payments
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The intervention's id
|
|
||||||
payment_id (str): The payment's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
intervention = get_object_or_404(Intervention, id=id)
|
|
||||||
payment = get_object_or_404(Payment, id=payment_id)
|
|
||||||
form = EditPaymentModalForm(request.POST or None, instance=intervention, payment=payment, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request=request,
|
|
||||||
msg_success=PAYMENT_EDITED,
|
|
||||||
redirect_url=reverse("intervention:detail", args=(payment.intervention_id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
class RemovePaymentView(BasePaymentView):
|
||||||
|
_MSG_SUCCESS = PAYMENT_REMOVED
|
||||||
|
_FORM_CLS = RemovePaymentModalForm
|
||||||
|
|||||||
14
ema/forms.py
14
ema/forms.py
@ -15,7 +15,8 @@ from compensation.forms.compensation import AbstractCompensationForm
|
|||||||
from ema.models import Ema, EmaDocument
|
from ema.models import Ema, EmaDocument
|
||||||
from intervention.models import Responsibility, Handler
|
from intervention.models import Responsibility, Handler
|
||||||
from konova.forms import SimpleGeomForm
|
from konova.forms import SimpleGeomForm
|
||||||
from konova.forms.modals import NewDocumentModalForm
|
from konova.forms.modals import NewDocumentModalForm, EditDocumentModalForm, RemoveDocumentModalForm, \
|
||||||
|
ResubmissionModalForm
|
||||||
from user.models import UserActionLogEntry
|
from user.models import UserActionLogEntry
|
||||||
|
|
||||||
|
|
||||||
@ -170,4 +171,13 @@ class EditEmaForm(NewEmaForm):
|
|||||||
|
|
||||||
|
|
||||||
class NewEmaDocumentModalForm(NewDocumentModalForm):
|
class NewEmaDocumentModalForm(NewDocumentModalForm):
|
||||||
document_model = EmaDocument
|
_DOCUMENT_CLS = EmaDocument
|
||||||
|
|
||||||
|
class EditEmaDocumentModalForm(EditDocumentModalForm):
|
||||||
|
_DOCUMENT_CLS = EmaDocument
|
||||||
|
|
||||||
|
class RemoveEmaDocumentModalForm(RemoveDocumentModalForm):
|
||||||
|
_DOCUMENT_CLS = EmaDocument
|
||||||
|
|
||||||
|
class EmaResubmissionModalForm(ResubmissionModalForm):
|
||||||
|
_MODEL_CLS = Ema
|
||||||
|
|||||||
19
ema/urls.py
19
ema/urls.py
@ -10,25 +10,26 @@ from django.urls import path
|
|||||||
from ema.views.action import NewEmaActionView, EditEmaActionView, RemoveEmaActionView
|
from ema.views.action import NewEmaActionView, EditEmaActionView, RemoveEmaActionView
|
||||||
from ema.views.deadline import NewEmaDeadlineView, EditEmaDeadlineView, RemoveEmaDeadlineView
|
from ema.views.deadline import NewEmaDeadlineView, EditEmaDeadlineView, RemoveEmaDeadlineView
|
||||||
from ema.views.document import NewEmaDocumentView, EditEmaDocumentView, RemoveEmaDocumentView, GetEmaDocumentView
|
from ema.views.document import NewEmaDocumentView, EditEmaDocumentView, RemoveEmaDocumentView, GetEmaDocumentView
|
||||||
from ema.views.ema import index_view, new_view, new_id_view, detail_view, edit_view, remove_view
|
from ema.views.ema import EmaIndexView, EmaIdentifierGeneratorView, EmaDetailView, EditEmaFormView, NewEmaFormView, \
|
||||||
|
RemoveEmaView
|
||||||
from ema.views.log import EmaLogView
|
from ema.views.log import EmaLogView
|
||||||
from ema.views.record import EmaRecordView
|
from ema.views.record import EmaRecordView
|
||||||
from ema.views.report import report_view
|
from ema.views.report import EmaReportView
|
||||||
from ema.views.resubmission import EmaResubmissionView
|
from ema.views.resubmission import EmaResubmissionView
|
||||||
from ema.views.share import EmaShareFormView, EmaShareByTokenView
|
from ema.views.share import EmaShareFormView, EmaShareByTokenView
|
||||||
from ema.views.state import NewEmaStateView, EditEmaStateView, RemoveEmaStateView
|
from ema.views.state import NewEmaStateView, EditEmaStateView, RemoveEmaStateView
|
||||||
|
|
||||||
app_name = "ema"
|
app_name = "ema"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", index_view, name="index"),
|
path("", EmaIndexView.as_view(), name="index"),
|
||||||
path("new/", new_view, name="new"),
|
path("new/", NewEmaFormView.as_view(), name="new"),
|
||||||
path("new/id", new_id_view, name="new-id"),
|
path("new/id", EmaIdentifierGeneratorView.as_view(), name="new-id"),
|
||||||
path("<id>", detail_view, name="detail"),
|
path("<id>", EmaDetailView.as_view(), name="detail"),
|
||||||
path('<id>/log', EmaLogView.as_view(), name='log'),
|
path('<id>/log', EmaLogView.as_view(), name='log'),
|
||||||
path('<id>/edit', edit_view, name='edit'),
|
path('<id>/edit', EditEmaFormView.as_view(), name='edit'),
|
||||||
path('<id>/remove', remove_view, name='remove'),
|
path('<id>/remove', RemoveEmaView.as_view(), name='remove'),
|
||||||
path('<id>/record', EmaRecordView.as_view(), name='record'),
|
path('<id>/record', EmaRecordView.as_view(), name='record'),
|
||||||
path('<id>/report', report_view, name='report'),
|
path('<id>/report', EmaReportView.as_view(), name='report'),
|
||||||
path('<id>/resub', EmaResubmissionView.as_view(), name='resubmission-create'),
|
path('<id>/resub', EmaResubmissionView.as_view(), name='resubmission-create'),
|
||||||
|
|
||||||
path('<id>/state/new', NewEmaStateView.as_view(), name='new-state'),
|
path('<id>/state/new', NewEmaStateView.as_view(), name='new-state'),
|
||||||
|
|||||||
@ -5,46 +5,31 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from ema.models import Ema
|
from ema.models import Ema
|
||||||
from konova.decorators import shared_access_required, conservation_office_group_required, login_required_modal
|
|
||||||
from konova.views.action import AbstractNewCompensationActionView, AbstractEditCompensationActionView, \
|
from konova.views.action import AbstractNewCompensationActionView, AbstractEditCompensationActionView, \
|
||||||
AbstractRemoveCompensationActionView
|
AbstractRemoveCompensationActionView
|
||||||
|
|
||||||
|
_EMA_ACCOUNT_DETAIL_URL_NAME = "ema:detail"
|
||||||
|
|
||||||
class NewEmaActionView(AbstractNewCompensationActionView):
|
class NewEmaActionView(AbstractNewCompensationActionView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = _EMA_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_ets_user()
|
||||||
|
|
||||||
class EditEmaActionView(AbstractEditCompensationActionView):
|
class EditEmaActionView(AbstractEditCompensationActionView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = _EMA_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@method_decorator(login_required)
|
return user.is_ets_user()
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveEmaActionView(AbstractRemoveCompensationActionView):
|
class RemoveEmaActionView(AbstractRemoveCompensationActionView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = _EMA_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@method_decorator(login_required)
|
return user.is_ets_user()
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,46 +5,30 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from ema.models import Ema
|
from ema.models import Ema
|
||||||
from konova.decorators import shared_access_required, conservation_office_group_required, login_required_modal
|
|
||||||
from konova.views.deadline import AbstractNewDeadlineView, AbstractRemoveDeadlineView, AbstractEditDeadlineView
|
from konova.views.deadline import AbstractNewDeadlineView, AbstractRemoveDeadlineView, AbstractEditDeadlineView
|
||||||
|
|
||||||
|
_EMA_DETAIL_URL_NAME = "ema:detail"
|
||||||
|
|
||||||
class NewEmaDeadlineView(AbstractNewDeadlineView):
|
class NewEmaDeadlineView(AbstractNewDeadlineView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = _EMA_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@method_decorator(login_required)
|
return user.is_ets_user()
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditEmaDeadlineView(AbstractEditDeadlineView):
|
class EditEmaDeadlineView(AbstractEditDeadlineView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = _EMA_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@method_decorator(login_required)
|
return user.is_ets_user()
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveEmaDeadlineView(AbstractRemoveDeadlineView):
|
class RemoveEmaDeadlineView(AbstractRemoveDeadlineView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = _EMA_DETAIL_URL_NAME
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_ets_user()
|
||||||
|
|||||||
@ -5,62 +5,41 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from ema.forms import NewEmaDocumentModalForm, RemoveEmaDocumentModalForm, EditEmaDocumentModalForm
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from ema.forms import NewEmaDocumentModalForm
|
|
||||||
from ema.models import Ema, EmaDocument
|
from ema.models import Ema, EmaDocument
|
||||||
from konova.decorators import shared_access_required, conservation_office_group_required, login_required_modal
|
|
||||||
from konova.forms.modals import EditDocumentModalForm
|
|
||||||
from konova.views.document import AbstractEditDocumentView, AbstractRemoveDocumentView, AbstractGetDocumentView, \
|
from konova.views.document import AbstractEditDocumentView, AbstractRemoveDocumentView, AbstractGetDocumentView, \
|
||||||
AbstractNewDocumentView
|
AbstractNewDocumentView
|
||||||
|
|
||||||
|
|
||||||
class NewEmaDocumentView(AbstractNewDocumentView):
|
class NewEmaDocumentView(AbstractNewDocumentView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
form = NewEmaDocumentModalForm
|
_FORM_CLS = NewEmaDocumentModalForm
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_ets_user()
|
||||||
|
|
||||||
class GetEmaDocumentView(AbstractGetDocumentView):
|
class GetEmaDocumentView(AbstractGetDocumentView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
document_model = EmaDocument
|
_DOCUMENT_CLS = EmaDocument
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_ets_user()
|
||||||
|
|
||||||
class RemoveEmaDocumentView(AbstractRemoveDocumentView):
|
class RemoveEmaDocumentView(AbstractRemoveDocumentView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
document_model = EmaDocument
|
_DOCUMENT_CLS = EmaDocument
|
||||||
|
_FORM_CLS = RemoveEmaDocumentModalForm
|
||||||
@method_decorator(login_required_modal)
|
_REDIRECT_URL = "ema:detail"
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_ets_user()
|
||||||
|
|
||||||
class EditEmaDocumentView(AbstractEditDocumentView):
|
class EditEmaDocumentView(AbstractEditDocumentView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
document_model = EmaDocument
|
_FORM_CLS = EditEmaDocumentModalForm
|
||||||
form = EditDocumentModalForm
|
_DOCUMENT_CLS = EmaDocument
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@method_decorator(login_required)
|
return user.is_ets_user()
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
339
ema/views/ema.py
339
ema/views/ema.py
@ -5,269 +5,112 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib import messages
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.shortcuts import get_object_or_404
|
||||||
from django.db.models import Sum
|
|
||||||
from django.http import HttpRequest, JsonResponse
|
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from ema.forms import NewEmaForm, EditEmaForm
|
from ema.forms import NewEmaForm, EditEmaForm
|
||||||
from ema.models import Ema
|
from ema.models import Ema
|
||||||
from ema.tables import EmaTable
|
from ema.tables import EmaTable
|
||||||
from konova.contexts import BaseContext
|
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView, BaseNewSpatialLocatedObjectFormView, \
|
||||||
from konova.decorators import shared_access_required, conservation_office_group_required, login_required_modal, \
|
BaseEditSpatialLocatedObjectFormView
|
||||||
uuid_required
|
from konova.views.detail import BaseDetailView
|
||||||
from konova.forms import SimpleGeomForm
|
from konova.views.remove import BaseRemoveModalFormView
|
||||||
from konova.forms.modals import RemoveModalForm
|
|
||||||
from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP
|
|
||||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
|
||||||
from konova.utils.message_templates import RECORDED_BLOCKS_EDIT, IDENTIFIER_REPLACED, FORM_INVALID, \
|
|
||||||
DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class EmaIndexView(LoginRequiredMixin, BaseIndexView):
|
||||||
def index_view(request: HttpRequest):
|
_TAB_TITLE = _("EMAs - Overview")
|
||||||
""" Renders the index view for EMAs
|
_INDEX_TABLE_CLS = EmaTable
|
||||||
|
|
||||||
Args:
|
def _get_queryset(self):
|
||||||
request (HttpRequest): The incoming request
|
qs = Ema.objects.filter(
|
||||||
|
deleted=None,
|
||||||
Returns:
|
).order_by(
|
||||||
|
"-modified__timestamp"
|
||||||
"""
|
)
|
||||||
template = "generic_index.html"
|
return qs
|
||||||
emas = Ema.objects.filter(
|
|
||||||
deleted=None,
|
|
||||||
).order_by(
|
|
||||||
"-modified__timestamp"
|
|
||||||
)
|
|
||||||
|
|
||||||
table = EmaTable(
|
|
||||||
request,
|
|
||||||
queryset=emas
|
|
||||||
)
|
|
||||||
context = {
|
|
||||||
"table": table,
|
|
||||||
TAB_TITLE_IDENTIFIER: _("EMAs - Overview"),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class NewEmaFormView(BaseNewSpatialLocatedObjectFormView):
|
||||||
@conservation_office_group_required
|
_FORM_CLS = NewEmaForm
|
||||||
def new_view(request: HttpRequest):
|
_MODEL_CLS = Ema
|
||||||
"""
|
_TEMPLATE = "ema/form/view.html"
|
||||||
Renders a view for a new eco account creation
|
_TAB_TITLE = _("New EMA")
|
||||||
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
Args:
|
def _user_has_permission(self, user, **kwargs):
|
||||||
request (HttpRequest): The incoming request
|
# User has to be an ets user
|
||||||
|
return user.is_ets_user()
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
template = "ema/form/view.html"
|
|
||||||
data_form = NewEmaForm(request.POST or None)
|
|
||||||
geom_form = SimpleGeomForm(request.POST or None, read_only=False)
|
|
||||||
if request.method == "POST":
|
|
||||||
if data_form.is_valid() and geom_form.is_valid():
|
|
||||||
generated_identifier = data_form.cleaned_data.get("identifier", None)
|
|
||||||
ema = data_form.save(request.user, geom_form)
|
|
||||||
if generated_identifier != ema.identifier:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
IDENTIFIER_REPLACED.format(
|
|
||||||
generated_identifier,
|
|
||||||
ema.identifier
|
|
||||||
)
|
|
||||||
)
|
|
||||||
messages.success(request, _("EMA {} added").format(ema.identifier))
|
|
||||||
if geom_form.has_geometry_simplified():
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
GEOMETRY_SIMPLIFIED
|
|
||||||
)
|
|
||||||
num_ignored_geometries = geom_form.get_num_geometries_ignored()
|
|
||||||
if num_ignored_geometries > 0:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
GEOMETRIES_IGNORED_TEMPLATE.format(num_ignored_geometries)
|
|
||||||
)
|
|
||||||
|
|
||||||
return redirect("ema:detail", id=ema.id)
|
|
||||||
else:
|
|
||||||
messages.error(request, FORM_INVALID, extra_tags="danger",)
|
|
||||||
else:
|
|
||||||
# For clarification: nothing in this case
|
|
||||||
pass
|
|
||||||
context = {
|
|
||||||
"form": data_form,
|
|
||||||
"geom_form": geom_form,
|
|
||||||
TAB_TITLE_IDENTIFIER: _("New EMA"),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class EditEmaFormView(BaseEditSpatialLocatedObjectFormView):
|
||||||
@conservation_office_group_required
|
_MODEL_CLS = Ema
|
||||||
def new_id_view(request: HttpRequest):
|
_FORM_CLS = EditEmaForm
|
||||||
""" JSON endpoint
|
_TEMPLATE = "ema/form/view.html"
|
||||||
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
_TAB_TITLE = _("Edit {}")
|
||||||
|
|
||||||
Provides fetching of free identifiers for e.g. AJAX calls
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# User has to be an ets user
|
||||||
|
return user.is_ets_user()
|
||||||
|
|
||||||
"""
|
|
||||||
tmp = Ema()
|
class EmaIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
|
||||||
identifier = tmp.generate_new_identifier()
|
_MODEL_CLS = Ema
|
||||||
while Ema.objects.filter(identifier=identifier).exists():
|
_REDIRECT_URL = "ema:index"
|
||||||
identifier = tmp.generate_new_identifier()
|
|
||||||
return JsonResponse(
|
def _user_has_permission(self, user, **kwargs):
|
||||||
data={
|
return user.is_ets_user()
|
||||||
"gen_data": identifier
|
|
||||||
|
|
||||||
|
class EmaDetailView(BaseDetailView):
|
||||||
|
_MODEL_CLS = Ema
|
||||||
|
_TEMPLATE = "ema/detail/view.html"
|
||||||
|
|
||||||
|
def _get_object(self, id: str):
|
||||||
|
""" Fetch object for detail view
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id (str): The record's id'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
ema = get_object_or_404(Ema, id=id, deleted=None)
|
||||||
|
return ema
|
||||||
|
|
||||||
|
def _get_detail_context(self, obj: Ema):
|
||||||
|
""" Generate object specific detail context for view
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (): The record
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Order states according to surface
|
||||||
|
before_states = obj.before_states.all().order_by("-surface")
|
||||||
|
after_states = obj.after_states.all().order_by("-surface")
|
||||||
|
|
||||||
|
# Precalculate logical errors between before- and after-states
|
||||||
|
# Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling
|
||||||
|
sum_before_states = obj.get_surface_before_states()
|
||||||
|
sum_after_states = obj.get_surface_after_states()
|
||||||
|
diff_states = abs(sum_before_states - sum_after_states)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
"before_states": before_states,
|
||||||
|
"after_states": after_states,
|
||||||
|
"sum_before_states": sum_before_states,
|
||||||
|
"sum_after_states": sum_after_states,
|
||||||
|
"diff_states": diff_states,
|
||||||
|
"has_finished_deadlines": obj.get_finished_deadlines().exists(),
|
||||||
}
|
}
|
||||||
)
|
return context
|
||||||
|
|
||||||
|
class RemoveEmaView(LoginRequiredMixin, BaseRemoveModalFormView):
|
||||||
|
_MODEL_CLS = Ema
|
||||||
|
_REDIRECT_URL = "ema:index"
|
||||||
|
|
||||||
@login_required
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@uuid_required
|
return user.is_ets_user()
|
||||||
def detail_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders the detail view of an EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The EMA id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
template = "ema/detail/view.html"
|
|
||||||
ema = get_object_or_404(Ema, id=id, deleted=None)
|
|
||||||
|
|
||||||
geom_form = SimpleGeomForm(instance=ema)
|
|
||||||
parcels = ema.get_underlying_parcels()
|
|
||||||
_user = request.user
|
|
||||||
is_entry_shared = ema.is_shared_with(_user)
|
|
||||||
|
|
||||||
# Order states according to surface
|
|
||||||
before_states = ema.before_states.all().order_by("-surface")
|
|
||||||
after_states = ema.after_states.all().order_by("-surface")
|
|
||||||
|
|
||||||
# Precalculate logical errors between before- and after-states
|
|
||||||
# Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling
|
|
||||||
sum_before_states = ema.get_surface_before_states()
|
|
||||||
sum_after_states = ema.get_surface_after_states()
|
|
||||||
diff_states = abs(sum_before_states - sum_after_states)
|
|
||||||
|
|
||||||
ema.set_status_messages(request)
|
|
||||||
|
|
||||||
requesting_user_is_only_shared_user = ema.is_only_shared_with(_user)
|
|
||||||
if requesting_user_is_only_shared_user:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
DO_NOT_FORGET_TO_SHARE
|
|
||||||
)
|
|
||||||
|
|
||||||
context = {
|
|
||||||
"obj": ema,
|
|
||||||
"geom_form": geom_form,
|
|
||||||
"parcels": parcels,
|
|
||||||
"is_entry_shared": is_entry_shared,
|
|
||||||
"before_states": before_states,
|
|
||||||
"after_states": after_states,
|
|
||||||
"sum_before_states": sum_before_states,
|
|
||||||
"sum_after_states": sum_after_states,
|
|
||||||
"diff_states": diff_states,
|
|
||||||
"is_default_member": _user.in_group(DEFAULT_GROUP),
|
|
||||||
"is_zb_member": _user.in_group(ZB_GROUP),
|
|
||||||
"is_ets_member": _user.in_group(ETS_GROUP),
|
|
||||||
"LANIS_LINK": ema.get_LANIS_link(),
|
|
||||||
TAB_TITLE_IDENTIFIER: f"{ema.identifier} - {ema.title}",
|
|
||||||
"has_finished_deadlines": ema.get_finished_deadlines().exists(),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@conservation_office_group_required
|
|
||||||
@shared_access_required(Ema, "id")
|
|
||||||
def edit_view(request: HttpRequest, id: str):
|
|
||||||
"""
|
|
||||||
Renders a view for editing compensations
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
template = "compensation/form/view.html"
|
|
||||||
# Get object from db
|
|
||||||
ema = get_object_or_404(Ema, id=id)
|
|
||||||
if ema.is_recorded:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
RECORDED_BLOCKS_EDIT
|
|
||||||
)
|
|
||||||
return redirect("ema:detail", id=id)
|
|
||||||
|
|
||||||
# Create forms, initialize with values from db/from POST request
|
|
||||||
data_form = EditEmaForm(request.POST or None, instance=ema)
|
|
||||||
geom_form = SimpleGeomForm(request.POST or None, read_only=False, instance=ema)
|
|
||||||
if request.method == "POST":
|
|
||||||
if data_form.is_valid() and geom_form.is_valid():
|
|
||||||
# The data form takes the geom form for processing, as well as the performing user
|
|
||||||
ema = data_form.save(request.user, geom_form)
|
|
||||||
messages.success(request, _("EMA {} edited").format(ema.identifier))
|
|
||||||
if geom_form.has_geometry_simplified():
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
GEOMETRY_SIMPLIFIED
|
|
||||||
)
|
|
||||||
|
|
||||||
num_ignored_geometries = geom_form.get_num_geometries_ignored()
|
|
||||||
if num_ignored_geometries > 0:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
GEOMETRIES_IGNORED_TEMPLATE.format(num_ignored_geometries)
|
|
||||||
)
|
|
||||||
|
|
||||||
return redirect("ema:detail", id=ema.id)
|
|
||||||
else:
|
|
||||||
messages.error(request, FORM_INVALID, extra_tags="danger",)
|
|
||||||
else:
|
|
||||||
# For clarification: nothing in this case
|
|
||||||
pass
|
|
||||||
context = {
|
|
||||||
"form": data_form,
|
|
||||||
"geom_form": geom_form,
|
|
||||||
TAB_TITLE_IDENTIFIER: _("Edit {}").format(ema.identifier),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required_modal
|
|
||||||
@login_required
|
|
||||||
@conservation_office_group_required
|
|
||||||
@shared_access_required(Ema, "id")
|
|
||||||
def remove_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a modal view for removing the EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The EMA's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
ema = get_object_or_404(Ema, id=id)
|
|
||||||
form = RemoveModalForm(request.POST or None, instance=ema, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request=request,
|
|
||||||
msg_success=_("EMA removed"),
|
|
||||||
redirect_url=reverse("ema:index"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|||||||
@ -5,20 +5,14 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from ema.models import Ema
|
from ema.models import Ema
|
||||||
from konova.decorators import shared_access_required, conservation_office_group_required, login_required_modal
|
|
||||||
from konova.views.log import AbstractLogView
|
from konova.views.log import AbstractLogView
|
||||||
|
|
||||||
|
|
||||||
class EmaLogView(AbstractLogView):
|
class EmaLogView(LoginRequiredMixin, AbstractLogView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@method_decorator(login_required)
|
return user.is_ets_user()
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,20 +5,12 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from ema.models import Ema
|
from ema.models import Ema
|
||||||
from konova.decorators import shared_access_required, conservation_office_group_required, login_required_modal
|
|
||||||
from konova.views.record import AbstractRecordView
|
from konova.views.record import AbstractRecordView
|
||||||
|
|
||||||
|
|
||||||
class EmaRecordView(AbstractRecordView):
|
class EmaRecordView(LoginRequiredMixin, AbstractRecordView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
|
_REDIRECT_URL = "ema:detail"
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,77 +5,36 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.http import HttpRequest
|
|
||||||
from django.shortcuts import get_object_or_404, render
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
|
from compensation.views.compensation.report import BaseCompensationReportView
|
||||||
from ema.models import Ema
|
from ema.models import Ema
|
||||||
from konova.contexts import BaseContext
|
from konova.sub_settings.django_settings import BASE_URL
|
||||||
from konova.decorators import uuid_required
|
from konova.utils.qrcode import QrCode
|
||||||
from konova.forms import SimpleGeomForm
|
|
||||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
|
||||||
from konova.utils.generators import generate_qr_code
|
|
||||||
|
|
||||||
@uuid_required
|
|
||||||
def report_view(request:HttpRequest, id: str):
|
|
||||||
""" Renders the public report view
|
|
||||||
|
|
||||||
Args:
|
class EmaReportView(BaseCompensationReportView):
|
||||||
request (HttpRequest): The incoming request
|
_TEMPLATE = "ema/report/report.html"
|
||||||
id (str): The id of the intervention
|
_MODEL = Ema
|
||||||
|
|
||||||
Returns:
|
def _get_report_context(self, obj):
|
||||||
|
report_url = BASE_URL + reverse("ema:report", args=(obj.id,))
|
||||||
|
qrcode_report = QrCode(report_url, 10)
|
||||||
|
qrcode_lanis = QrCode(obj.get_LANIS_link(), 7)
|
||||||
|
|
||||||
"""
|
generic_compensation_report_context = self._get_compensation_report_context(obj)
|
||||||
# Reuse the compensation report template since EMAs are structurally identical
|
|
||||||
template = "ema/report/report.html"
|
|
||||||
ema = get_object_or_404(Ema, id=id)
|
|
||||||
|
|
||||||
tab_title = _("Report {}").format(ema.identifier)
|
report_context = {
|
||||||
# If intervention is not recorded (yet or currently) we need to render another template without any data
|
"qrcode": {
|
||||||
if not ema.is_ready_for_publish():
|
"img": qrcode_report.get_img(),
|
||||||
template = "report/unavailable.html"
|
"url": qrcode_report.get_content(),
|
||||||
context = {
|
},
|
||||||
TAB_TITLE_IDENTIFIER: tab_title,
|
"qrcode_lanis": {
|
||||||
|
"img": qrcode_lanis.get_img(),
|
||||||
|
"url": qrcode_lanis.get_content(),
|
||||||
|
},
|
||||||
|
"is_entry_shared": False, # disables action buttons during rendering
|
||||||
|
"tables_scrollable": False,
|
||||||
}
|
}
|
||||||
context = BaseContext(request, context).context
|
report_context.update(generic_compensation_report_context)
|
||||||
return render(request, template, context)
|
return report_context
|
||||||
|
|
||||||
# Prepare data for map viewer
|
|
||||||
geom_form = SimpleGeomForm(
|
|
||||||
instance=ema,
|
|
||||||
)
|
|
||||||
parcels = ema.get_underlying_parcels()
|
|
||||||
|
|
||||||
qrcode_url = request.build_absolute_uri(reverse("ema:report", args=(id,)))
|
|
||||||
qrcode_img = generate_qr_code(qrcode_url, 10)
|
|
||||||
qrcode_lanis_url = ema.get_LANIS_link()
|
|
||||||
qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7)
|
|
||||||
|
|
||||||
# Order states by surface
|
|
||||||
before_states = ema.before_states.all().order_by("-surface").prefetch_related("biotope_type")
|
|
||||||
after_states = ema.after_states.all().order_by("-surface").prefetch_related("biotope_type")
|
|
||||||
actions = ema.actions.all().prefetch_related("action_type")
|
|
||||||
|
|
||||||
context = {
|
|
||||||
"obj": ema,
|
|
||||||
"qrcode": {
|
|
||||||
"img": qrcode_img,
|
|
||||||
"url": qrcode_url
|
|
||||||
},
|
|
||||||
"qrcode_lanis": {
|
|
||||||
"img": qrcode_img_lanis,
|
|
||||||
"url": qrcode_lanis_url
|
|
||||||
},
|
|
||||||
"is_entry_shared": False, # disables action buttons during rendering
|
|
||||||
"before_states": before_states,
|
|
||||||
"after_states": after_states,
|
|
||||||
"geom_form": geom_form,
|
|
||||||
"parcels": parcels,
|
|
||||||
"actions": actions,
|
|
||||||
"tables_scrollable": False,
|
|
||||||
TAB_TITLE_IDENTIFIER: tab_title,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
@ -5,22 +5,16 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from ema.forms import EmaResubmissionModalForm
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from ema.models import Ema
|
from ema.models import Ema
|
||||||
from konova.decorators import shared_access_required, conservation_office_group_required, login_required_modal
|
|
||||||
from konova.views.resubmission import AbstractResubmissionView
|
from konova.views.resubmission import AbstractResubmissionView
|
||||||
|
|
||||||
|
|
||||||
class EmaResubmissionView(AbstractResubmissionView):
|
class EmaResubmissionView(AbstractResubmissionView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
redirect_url_base = "ema:detail"
|
_FORM_CLS = EmaResubmissionModalForm
|
||||||
form_action_url_base = "ema:resubmission-create"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
action_url = "ema:resubmission-create"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@method_decorator(login_required)
|
return user.is_ets_user()
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,29 +5,17 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from ema.models import Ema
|
from ema.models import Ema
|
||||||
from konova.decorators import conservation_office_group_required, shared_access_required, login_required_modal
|
|
||||||
from konova.views.share import AbstractShareByTokenView, AbstractShareFormView
|
from konova.views.share import AbstractShareByTokenView, AbstractShareFormView
|
||||||
|
|
||||||
|
|
||||||
class EmaShareByTokenView(AbstractShareByTokenView):
|
class EmaShareByTokenView(AbstractShareByTokenView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EmaShareFormView(AbstractShareFormView):
|
class EmaShareFormView(AbstractShareFormView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@method_decorator(login_required)
|
return user.is_ets_user()
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
@ -5,46 +5,30 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from ema.models import Ema
|
from ema.models import Ema
|
||||||
from konova.decorators import conservation_office_group_required, shared_access_required, login_required_modal
|
|
||||||
from konova.views.state import AbstractNewCompensationStateView, AbstractEditCompensationStateView, \
|
from konova.views.state import AbstractNewCompensationStateView, AbstractEditCompensationStateView, \
|
||||||
AbstractRemoveCompensationStateView
|
AbstractRemoveCompensationStateView
|
||||||
|
|
||||||
|
|
||||||
class NewEmaStateView(AbstractNewCompensationStateView):
|
class NewEmaStateView(AbstractNewCompensationStateView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@method_decorator(login_required)
|
return user.is_ets_user()
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditEmaStateView(AbstractEditCompensationStateView):
|
class EditEmaStateView(AbstractEditCompensationStateView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@method_decorator(login_required)
|
return user.is_ets_user()
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveEmaStateView(AbstractRemoveCompensationStateView):
|
class RemoveEmaStateView(AbstractRemoveCompensationStateView):
|
||||||
model = Ema
|
_MODEL_CLS = Ema
|
||||||
redirect_url = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
@method_decorator(login_required)
|
return user.is_ets_user()
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Ema, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -172,7 +172,8 @@ class EditEcoAccountDeductionModalForm(NewEcoAccountDeductionModalForm):
|
|||||||
deduction = None
|
deduction = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.deduction = kwargs.pop("deduction", None)
|
deduction_id = kwargs.pop("deduction_id", None)
|
||||||
|
self.deduction = EcoAccountDeduction.objects.get(id=deduction_id)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.form_title = _("Edit Deduction")
|
self.form_title = _("Edit Deduction")
|
||||||
form_data = {
|
form_data = {
|
||||||
@ -252,19 +253,20 @@ class RemoveEcoAccountDeductionModalForm(RemoveModalForm):
|
|||||||
Can be used for anything, where removing shall be confirmed by the user a second time.
|
Can be used for anything, where removing shall be confirmed by the user a second time.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
deduction = None
|
_DEDUCTION_OBJ = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
deduction = kwargs.pop("deduction", None)
|
deduction_id = kwargs.pop("deduction_id", None)
|
||||||
self.deduction = deduction
|
deduction = EcoAccountDeduction.objects.get(id=deduction_id)
|
||||||
|
self._DEDUCTION_OBJ = deduction
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
self.deduction.intervention.mark_as_edited(self.user, edit_comment=DEDUCTION_REMOVED)
|
self._DEDUCTION_OBJ.intervention.mark_as_edited(self.user, edit_comment=DEDUCTION_REMOVED)
|
||||||
self.deduction.account.mark_as_edited(self.user, edit_comment=DEDUCTION_REMOVED)
|
self._DEDUCTION_OBJ.account.mark_as_edited(self.user, edit_comment=DEDUCTION_REMOVED)
|
||||||
self.deduction.delete()
|
self._DEDUCTION_OBJ.delete()
|
||||||
|
|
||||||
def check_for_recorded_instance(self):
|
def check_for_recorded_instance(self):
|
||||||
if self.deduction.intervention.is_recorded:
|
if self._DEDUCTION_OBJ.intervention.is_recorded:
|
||||||
self.block_form()
|
self.block_form()
|
||||||
|
|||||||
@ -6,11 +6,11 @@ Created on: 18.08.22
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from intervention.models import InterventionDocument
|
from intervention.models import InterventionDocument
|
||||||
from konova.forms.modals import NewDocumentModalForm
|
from konova.forms.modals import NewDocumentModalForm, EditDocumentModalForm, RemoveDocumentModalForm
|
||||||
|
|
||||||
|
|
||||||
class NewInterventionDocumentModalForm(NewDocumentModalForm):
|
class NewInterventionDocumentModalForm(NewDocumentModalForm):
|
||||||
document_model = InterventionDocument
|
_DOCUMENT_CLS = InterventionDocument
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
""" Extension of regular NewDocumentModalForm
|
""" Extension of regular NewDocumentModalForm
|
||||||
@ -28,3 +28,31 @@ class NewInterventionDocumentModalForm(NewDocumentModalForm):
|
|||||||
self.instance.send_data_to_egon()
|
self.instance.send_data_to_egon()
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
class EditInterventionDocumentModalForm(EditDocumentModalForm):
|
||||||
|
_DOCUMENT_CLS = InterventionDocument
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
""" Extension of regular EditDocumentModalForm
|
||||||
|
|
||||||
|
Checks whether payments exist on the intervention and sends the data to EGON
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
doc = super().save(*args, **kwargs)
|
||||||
|
self.instance.send_data_to_egon()
|
||||||
|
|
||||||
|
return doc
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveInterventionDocumentModalForm(RemoveDocumentModalForm):
|
||||||
|
_DOCUMENT_CLS = InterventionDocument
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
self.instance.send_data_to_egon()
|
||||||
|
|||||||
11
intervention/forms/modals/resubmission.py
Normal file
11
intervention/forms/modals/resubmission.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
"""
|
||||||
|
Author: Michel Peltriaux
|
||||||
|
Created on: 21.10.25
|
||||||
|
|
||||||
|
"""
|
||||||
|
from intervention.models import Intervention
|
||||||
|
from konova.forms.modals import ResubmissionModalForm
|
||||||
|
|
||||||
|
|
||||||
|
class InterventionResubmissionModalForm(ResubmissionModalForm):
|
||||||
|
_MODEL_CLS = Intervention
|
||||||
@ -7,9 +7,10 @@ Created on: 18.08.22
|
|||||||
"""
|
"""
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from intervention.models import RevocationDocument
|
from intervention.models import RevocationDocument, Revocation
|
||||||
from konova.forms.modals import BaseModalForm, RemoveModalForm
|
from konova.forms.modals import BaseModalForm, RemoveModalForm
|
||||||
from konova.utils import validators
|
from konova.utils import validators
|
||||||
from konova.utils.message_templates import REVOCATION_ADDED, REVOCATION_EDITED
|
from konova.utils.message_templates import REVOCATION_ADDED, REVOCATION_EDITED
|
||||||
@ -75,7 +76,8 @@ class EditRevocationModalForm(NewRevocationModalForm):
|
|||||||
revocation = None
|
revocation = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.revocation = kwargs.pop("revocation", None)
|
revocation_id = kwargs.pop("revocation_id", None)
|
||||||
|
self.revocation = get_object_or_404(Revocation, id=revocation_id)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.form_title = _("Edit revocation")
|
self.form_title = _("Edit revocation")
|
||||||
try:
|
try:
|
||||||
@ -104,8 +106,8 @@ class RemoveRevocationModalForm(RemoveModalForm):
|
|||||||
revocation = None
|
revocation = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
revocation = kwargs.pop("revocation", None)
|
revocation_id = kwargs.pop("revocation_id", None)
|
||||||
self.revocation = revocation
|
self.revocation = get_object_or_404(Revocation, id=revocation_id)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
|||||||
@ -280,7 +280,7 @@ class EditRevocationModalFormTestCase(NewRevocationModalFormTestCase):
|
|||||||
data,
|
data,
|
||||||
request=self.request,
|
request=self.request,
|
||||||
instance=self.intervention,
|
instance=self.intervention,
|
||||||
revocation=self.revoc
|
revocation_id=self.revoc.id
|
||||||
)
|
)
|
||||||
self.assertTrue(form.is_valid(), msg=form.errors)
|
self.assertTrue(form.is_valid(), msg=form.errors)
|
||||||
obj = form.save()
|
obj = form.save()
|
||||||
@ -302,7 +302,7 @@ class RemoveRevocationModalFormTestCase(EditRevocationModalFormTestCase):
|
|||||||
form = RemoveRevocationModalForm(
|
form = RemoveRevocationModalForm(
|
||||||
request=self.request,
|
request=self.request,
|
||||||
instance=self.intervention,
|
instance=self.intervention,
|
||||||
revocation=self.revoc,
|
revocation_id=self.revoc.id,
|
||||||
)
|
)
|
||||||
self.assertEqual(form.instance, self.intervention)
|
self.assertEqual(form.instance, self.intervention)
|
||||||
self.assertEqual(form.revocation, self.revoc)
|
self.assertEqual(form.revocation, self.revoc)
|
||||||
@ -317,7 +317,7 @@ class RemoveRevocationModalFormTestCase(EditRevocationModalFormTestCase):
|
|||||||
data,
|
data,
|
||||||
request=self.request,
|
request=self.request,
|
||||||
instance=self.intervention,
|
instance=self.intervention,
|
||||||
revocation=self.revoc
|
revocation_id=self.revoc.id
|
||||||
)
|
)
|
||||||
self.assertTrue(form.is_valid(), msg=form.errors)
|
self.assertTrue(form.is_valid(), msg=form.errors)
|
||||||
form.save()
|
form.save()
|
||||||
|
|||||||
@ -8,35 +8,36 @@ Created on: 30.11.20
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from intervention.autocomplete.intervention import InterventionAutocomplete
|
from intervention.autocomplete.intervention import InterventionAutocomplete
|
||||||
from intervention.views.check import check_view
|
from intervention.views.check import InterventionCheckView
|
||||||
from intervention.views.compensation import remove_compensation_view
|
from intervention.views.compensation import remove_compensation_view
|
||||||
from intervention.views.deduction import NewInterventionDeductionView, EditInterventionDeductionView, \
|
from intervention.views.deduction import NewInterventionDeductionView, EditInterventionDeductionView, \
|
||||||
RemoveInterventionDeductionView
|
RemoveInterventionDeductionView
|
||||||
from intervention.views.document import NewInterventionDocumentView, GetInterventionDocumentView, \
|
from intervention.views.document import NewInterventionDocumentView, GetInterventionDocumentView, \
|
||||||
RemoveInterventionDocumentView, EditInterventionDocumentView
|
RemoveInterventionDocumentView, EditInterventionDocumentView
|
||||||
from intervention.views.intervention import index_view, new_view, new_id_view, detail_view, edit_view, remove_view
|
from intervention.views.intervention import InterventionIndexView, InterventionIdentifierGeneratorView, \
|
||||||
|
InterventionDetailView, NewInterventionFormView, EditInterventionFormView, RemoveInterventionView
|
||||||
from intervention.views.log import InterventionLogView
|
from intervention.views.log import InterventionLogView
|
||||||
from intervention.views.record import InterventionRecordView
|
from intervention.views.record import InterventionRecordView
|
||||||
from intervention.views.report import report_view
|
from intervention.views.report import InterventionReportView
|
||||||
from intervention.views.resubmission import InterventionResubmissionView
|
from intervention.views.resubmission import InterventionResubmissionView
|
||||||
from intervention.views.revocation import new_revocation_view, edit_revocation_view, remove_revocation_view, \
|
from intervention.views.revocation import NewRevocationView, GetRevocationDocumentView, EditRevocationView, \
|
||||||
get_revocation_view
|
RemoveRevocationView
|
||||||
from intervention.views.share import InterventionShareFormView, InterventionShareByTokenView
|
from intervention.views.share import InterventionShareFormView, InterventionShareByTokenView
|
||||||
|
|
||||||
app_name = "intervention"
|
app_name = "intervention"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", index_view, name="index"),
|
path("", InterventionIndexView.as_view(), name="index"),
|
||||||
path('new/', new_view, name='new'),
|
path('new/', NewInterventionFormView.as_view(), name='new'),
|
||||||
path('new/id', new_id_view, name='new-id'),
|
path('new/id', InterventionIdentifierGeneratorView.as_view(), name='new-id'),
|
||||||
path('<id>', detail_view, name='detail'),
|
path('<id>', InterventionDetailView.as_view(), name='detail'),
|
||||||
path('<id>/log', InterventionLogView.as_view(), name='log'),
|
path('<id>/log', InterventionLogView.as_view(), name='log'),
|
||||||
path('<id>/edit', edit_view, name='edit'),
|
path('<id>/edit', EditInterventionFormView.as_view(), name='edit'),
|
||||||
path('<id>/remove', remove_view, name='remove'),
|
path('<id>/remove', RemoveInterventionView.as_view(), name='remove'),
|
||||||
path('<id>/share/<token>', InterventionShareByTokenView.as_view(), name='share-token'),
|
path('<id>/share/<token>', InterventionShareByTokenView.as_view(), name='share-token'),
|
||||||
path('<id>/share', InterventionShareFormView.as_view(), name='share-form'),
|
path('<id>/share', InterventionShareFormView.as_view(), name='share-form'),
|
||||||
path('<id>/check', check_view, name='check'),
|
path('<id>/check', InterventionCheckView.as_view(), name='check'),
|
||||||
path('<id>/record', InterventionRecordView.as_view(), name='record'),
|
path('<id>/record', InterventionRecordView.as_view(), name='record'),
|
||||||
path('<id>/report', report_view, name='report'),
|
path('<id>/report', InterventionReportView.as_view(), name='report'),
|
||||||
path('<id>/resub', InterventionResubmissionView.as_view(), name='resubmission-create'),
|
path('<id>/resub', InterventionResubmissionView.as_view(), name='resubmission-create'),
|
||||||
|
|
||||||
# Compensations
|
# Compensations
|
||||||
@ -54,10 +55,10 @@ urlpatterns = [
|
|||||||
path('<id>/deduction/<deduction_id>/remove', RemoveInterventionDeductionView.as_view(), name='remove-deduction'),
|
path('<id>/deduction/<deduction_id>/remove', RemoveInterventionDeductionView.as_view(), name='remove-deduction'),
|
||||||
|
|
||||||
# Revocation routes
|
# Revocation routes
|
||||||
path('<id>/revocation/new', new_revocation_view, name='new-revocation'),
|
path('<id>/revocation/new', NewRevocationView.as_view(), name='new-revocation'),
|
||||||
path('<id>/revocation/<revocation_id>/edit', edit_revocation_view, name='edit-revocation'),
|
path('<id>/revocation/<revocation_id>/edit', EditRevocationView.as_view(), name='edit-revocation'),
|
||||||
path('<id>/revocation/<revocation_id>/remove', remove_revocation_view, name='remove-revocation'),
|
path('<id>/revocation/<revocation_id>/remove', RemoveRevocationView.as_view(), name='remove-revocation'),
|
||||||
path('revocation/<doc_id>', get_revocation_view, name='get-doc-revocation'),
|
path('revocation/<doc_id>', GetRevocationDocumentView.as_view(), name='get-doc-revocation'),
|
||||||
|
|
||||||
# Autocomplete
|
# Autocomplete
|
||||||
path("atcmplt/interventions", InterventionAutocomplete.as_view(), name="autocomplete"),
|
path("atcmplt/interventions", InterventionAutocomplete.as_view(), name="autocomplete"),
|
||||||
|
|||||||
@ -5,35 +5,24 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.http import HttpRequest
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from intervention.forms.modals.check import CheckModalForm
|
from intervention.forms.modals.check import CheckModalForm
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.decorators import registration_office_group_required, shared_access_required
|
from konova.views.base import BaseModalFormView
|
||||||
from konova.utils.message_templates import INTERVENTION_INVALID
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class InterventionCheckView(LoginRequiredMixin, BaseModalFormView):
|
||||||
@registration_office_group_required
|
_MODEL_CLS = Intervention
|
||||||
@shared_access_required(Intervention, "id")
|
_FORM_CLS = CheckModalForm
|
||||||
def check_view(request: HttpRequest, id: str):
|
_MSG_SUCCESS = _("Check performed")
|
||||||
""" Renders check form for an intervention
|
_REDIRECT_URL = "intervention:detail"
|
||||||
|
|
||||||
Args:
|
def _user_has_permission(self, user, **kwargs):
|
||||||
request (HttpRequest): The incoming request
|
return user.is_zb_user()
|
||||||
id (str): Intervention's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
intervention = get_object_or_404(Intervention, id=id)
|
|
||||||
form = CheckModalForm(request.POST or None, instance=intervention, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=_("Check performed"),
|
|
||||||
msg_error=INTERVENTION_INVALID
|
|
||||||
)
|
|
||||||
|
|
||||||
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
redirect_url = super()._get_redirect_url(*args, **kwargs)
|
||||||
|
redirect_url += "#related_data"
|
||||||
|
return redirect_url
|
||||||
|
|||||||
@ -5,51 +5,27 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.decorators import default_group_required, shared_access_required
|
from konova.utils.message_templates import DEDUCTION_ADDED, DEDUCTION_EDITED, DEDUCTION_REMOVED
|
||||||
from konova.views.deduction import AbstractNewDeductionView, AbstractEditDeductionView, AbstractRemoveDeductionView
|
from konova.views.deduction import AbstractNewDeductionView, AbstractEditDeductionView, AbstractRemoveDeductionView
|
||||||
|
|
||||||
|
_INTERVENTION_DETAIL_URL_NAME = "intervention:detail"
|
||||||
|
|
||||||
class NewInterventionDeductionView(AbstractNewDeductionView):
|
class NewInterventionDeductionView(LoginRequiredMixin, AbstractNewDeductionView):
|
||||||
def _custom_check(self, obj):
|
_MODEL_CLS = Intervention
|
||||||
pass
|
_MSG_SUCCESS = DEDUCTION_ADDED
|
||||||
|
_REDIRECT_URL = _INTERVENTION_DETAIL_URL_NAME
|
||||||
model = Intervention
|
|
||||||
redirect_url = "intervention:detail"
|
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Intervention, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditInterventionDeductionView(AbstractEditDeductionView):
|
class EditInterventionDeductionView(LoginRequiredMixin, AbstractEditDeductionView):
|
||||||
def _custom_check(self, obj):
|
_MODEL_CLS = Intervention
|
||||||
pass
|
_MSG_SUCCESS = DEDUCTION_EDITED
|
||||||
|
_REDIRECT_URL = _INTERVENTION_DETAIL_URL_NAME
|
||||||
model = Intervention
|
|
||||||
redirect_url = "intervention:detail"
|
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Intervention, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveInterventionDeductionView(AbstractRemoveDeductionView):
|
class RemoveInterventionDeductionView(LoginRequiredMixin, AbstractRemoveDeductionView):
|
||||||
def _custom_check(self, obj):
|
_MODEL_CLS = Intervention
|
||||||
pass
|
_MSG_SUCCESS = DEDUCTION_REMOVED
|
||||||
|
_REDIRECT_URL = _INTERVENTION_DETAIL_URL_NAME
|
||||||
model = Intervention
|
|
||||||
redirect_url = "intervention:detail"
|
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Intervention, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,59 +5,33 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from intervention.forms.modals.document import NewInterventionDocumentModalForm, EditInterventionDocumentModalForm, \
|
||||||
from django.utils.decorators import method_decorator
|
RemoveInterventionDocumentModalForm
|
||||||
|
|
||||||
from intervention.forms.modals.document import NewInterventionDocumentModalForm
|
|
||||||
from intervention.models import Intervention, InterventionDocument
|
from intervention.models import Intervention, InterventionDocument
|
||||||
from konova.decorators import default_group_required, shared_access_required
|
|
||||||
from konova.forms.modals import EditDocumentModalForm
|
|
||||||
from konova.views.document import AbstractNewDocumentView, AbstractGetDocumentView, AbstractRemoveDocumentView, \
|
from konova.views.document import AbstractNewDocumentView, AbstractGetDocumentView, AbstractRemoveDocumentView, \
|
||||||
AbstractEditDocumentView
|
AbstractEditDocumentView
|
||||||
|
|
||||||
|
|
||||||
class NewInterventionDocumentView(AbstractNewDocumentView):
|
class NewInterventionDocumentView(AbstractNewDocumentView):
|
||||||
model = Intervention
|
_MODEL_CLS = Intervention
|
||||||
form = NewInterventionDocumentModalForm
|
_DOCUMENT_MODEL = InterventionDocument
|
||||||
redirect_url = "intervention:detail"
|
_FORM_CLS = NewInterventionDocumentModalForm
|
||||||
|
_REDIRECT_URL = "intervention:detail"
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Intervention, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class GetInterventionDocumentView(AbstractGetDocumentView):
|
class GetInterventionDocumentView(AbstractGetDocumentView):
|
||||||
model = Intervention
|
_MODEL_CLS = Intervention
|
||||||
document_model = InterventionDocument
|
_DOCUMENT_CLS = InterventionDocument
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Intervention, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveInterventionDocumentView(AbstractRemoveDocumentView):
|
class RemoveInterventionDocumentView(AbstractRemoveDocumentView):
|
||||||
model = Intervention
|
_MODEL_CLS = Intervention
|
||||||
document_model = InterventionDocument
|
_DOCUMENT_CLS = InterventionDocument
|
||||||
|
_FORM_CLS = RemoveInterventionDocumentModalForm
|
||||||
@method_decorator(login_required)
|
_REDIRECT_URL = "intervention:detail"
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Intervention, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EditInterventionDocumentView(AbstractEditDocumentView):
|
class EditInterventionDocumentView(AbstractEditDocumentView):
|
||||||
model = Intervention
|
_MODEL_CLS = Intervention
|
||||||
document_model = InterventionDocument
|
_DOCUMENT_CLS = InterventionDocument
|
||||||
form = EditDocumentModalForm
|
_FORM_CLS = EditInterventionDocumentModalForm
|
||||||
redirect_url = "intervention:detail"
|
_REDIRECT_URL = "intervention:detail"
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Intervention, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -7,207 +7,115 @@ Created on: 19.08.22
|
|||||||
"""
|
"""
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.http import JsonResponse, HttpRequest
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.http import HttpRequest
|
||||||
from django.shortcuts import get_object_or_404, render, redirect
|
from django.shortcuts import get_object_or_404, render, redirect
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from intervention.forms.intervention import EditInterventionForm, NewInterventionForm
|
from intervention.forms.intervention import EditInterventionForm, NewInterventionForm
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from intervention.tables import InterventionTable
|
from intervention.tables import InterventionTable
|
||||||
from konova.contexts import BaseContext
|
from konova.contexts import BaseContext
|
||||||
from konova.decorators import default_group_required, shared_access_required, any_group_check, login_required_modal, \
|
from konova.decorators import default_group_required, shared_access_required
|
||||||
uuid_required
|
|
||||||
from konova.forms import SimpleGeomForm
|
from konova.forms import SimpleGeomForm
|
||||||
from konova.forms.modals import RemoveModalForm
|
|
||||||
from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP
|
|
||||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
||||||
from konova.utils.message_templates import DATA_CHECKED_PREVIOUSLY_TEMPLATE, RECORDED_BLOCKS_EDIT, \
|
from konova.utils.message_templates import DATA_CHECKED_PREVIOUSLY_TEMPLATE, RECORDED_BLOCKS_EDIT, \
|
||||||
CHECK_STATE_RESET, FORM_INVALID, IDENTIFIER_REPLACED, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, \
|
CHECK_STATE_RESET, FORM_INVALID, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
|
||||||
GEOMETRIES_IGNORED_TEMPLATE
|
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView, BaseNewSpatialLocatedObjectFormView, \
|
||||||
|
BaseEditSpatialLocatedObjectFormView
|
||||||
|
from konova.views.detail import BaseDetailView
|
||||||
|
from konova.views.remove import BaseRemoveModalFormView
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class InterventionIndexView(LoginRequiredMixin, BaseIndexView):
|
||||||
@any_group_check
|
_INDEX_TABLE_CLS = InterventionTable
|
||||||
def index_view(request: HttpRequest):
|
_TAB_TITLE = _("Interventions - Overview")
|
||||||
"""
|
|
||||||
Renders the index view for Interventions
|
|
||||||
|
|
||||||
Args:
|
def _get_queryset(self):
|
||||||
request (HttpRequest): The incoming request
|
qs = Intervention.objects.filter(
|
||||||
|
deleted=None,
|
||||||
Returns:
|
).select_related(
|
||||||
A rendered view
|
"legal"
|
||||||
"""
|
).order_by(
|
||||||
template = "generic_index.html"
|
"-modified__timestamp"
|
||||||
|
)
|
||||||
# Filtering by user access is performed in table filter inside InterventionTableFilter class
|
return qs
|
||||||
interventions = Intervention.objects.filter(
|
|
||||||
deleted=None, # not deleted
|
|
||||||
).select_related(
|
|
||||||
"legal"
|
|
||||||
).order_by(
|
|
||||||
"-modified__timestamp"
|
|
||||||
)
|
|
||||||
table = InterventionTable(
|
|
||||||
request=request,
|
|
||||||
queryset=interventions
|
|
||||||
)
|
|
||||||
context = {
|
|
||||||
"table": table,
|
|
||||||
TAB_TITLE_IDENTIFIER: _("Interventions - Overview"),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class NewInterventionFormView(BaseNewSpatialLocatedObjectFormView):
|
||||||
@default_group_required
|
_MODEL_CLS = Intervention
|
||||||
def new_view(request: HttpRequest):
|
_FORM_CLS = NewInterventionForm
|
||||||
"""
|
_TEMPLATE = "intervention/form/view.html"
|
||||||
Renders a view for a new intervention creation
|
_REDIRECT_URL = "intervention:detail"
|
||||||
|
_TAB_TITLE = _("New intervention")
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
template = "intervention/form/view.html"
|
|
||||||
data_form = NewInterventionForm(request.POST or None)
|
|
||||||
geom_form = SimpleGeomForm(request.POST or None, read_only=False)
|
|
||||||
if request.method == "POST":
|
|
||||||
if data_form.is_valid() and geom_form.is_valid():
|
|
||||||
generated_identifier = data_form.cleaned_data.get("identifier", None)
|
|
||||||
intervention = data_form.save(request.user, geom_form)
|
|
||||||
if generated_identifier != intervention.identifier:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
IDENTIFIER_REPLACED.format(
|
|
||||||
generated_identifier,
|
|
||||||
intervention.identifier
|
|
||||||
)
|
|
||||||
)
|
|
||||||
messages.success(request, _("Intervention {} added").format(intervention.identifier))
|
|
||||||
if geom_form.has_geometry_simplified():
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
GEOMETRY_SIMPLIFIED
|
|
||||||
)
|
|
||||||
|
|
||||||
num_ignored_geometries = geom_form.get_num_geometries_ignored()
|
|
||||||
if num_ignored_geometries > 0:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
GEOMETRIES_IGNORED_TEMPLATE.format(num_ignored_geometries)
|
|
||||||
)
|
|
||||||
|
|
||||||
return redirect("intervention:detail", id=intervention.id)
|
|
||||||
else:
|
|
||||||
messages.error(request, FORM_INVALID, extra_tags="danger",)
|
|
||||||
else:
|
|
||||||
# For clarification: nothing in this case
|
|
||||||
pass
|
|
||||||
context = {
|
|
||||||
"form": data_form,
|
|
||||||
"geom_form": geom_form,
|
|
||||||
TAB_TITLE_IDENTIFIER: _("New intervention"),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class EditInterventionFormView(BaseEditSpatialLocatedObjectFormView):
|
||||||
@default_group_required
|
_MODEL_CLS = Intervention
|
||||||
def new_id_view(request: HttpRequest):
|
_FORM_CLS = EditInterventionForm
|
||||||
""" JSON endpoint
|
_TEMPLATE = "intervention/form/view.html"
|
||||||
|
_REDIRECT_URL = "intervention:detail"
|
||||||
|
_TAB_TITLE = _("Edit {}")
|
||||||
|
|
||||||
Provides fetching of free identifiers for e.g. AJAX calls
|
|
||||||
|
|
||||||
"""
|
class InterventionIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
|
||||||
tmp_intervention = Intervention()
|
_MODEL_CLS = Intervention
|
||||||
identifier = tmp_intervention.generate_new_identifier()
|
_REDIRECT_URL = "intervention:index"
|
||||||
while Intervention.objects.filter(identifier=identifier).exists():
|
|
||||||
identifier = tmp_intervention.generate_new_identifier()
|
|
||||||
return JsonResponse(
|
class InterventionDetailView(BaseDetailView):
|
||||||
data={
|
_MODEL_CLS = Intervention
|
||||||
"gen_data": identifier
|
_TEMPLATE = "intervention/detail/view.html"
|
||||||
|
|
||||||
|
def _get_object(self, id: str):
|
||||||
|
""" Returns the intervention
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id (str): The intervention's id
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
obj (Intervention): The intervention
|
||||||
|
"""
|
||||||
|
# Fetch data, filter out deleted related data
|
||||||
|
obj = get_object_or_404(
|
||||||
|
self._MODEL_CLS.objects.select_related(
|
||||||
|
"geometry",
|
||||||
|
"legal",
|
||||||
|
"responsible",
|
||||||
|
).prefetch_related(
|
||||||
|
"legal__revocations",
|
||||||
|
),
|
||||||
|
id=id,
|
||||||
|
deleted=None
|
||||||
|
)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def _get_detail_context(self, obj: Intervention):
|
||||||
|
""" Generate object specific detail context for view
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (): The record
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
compensations = obj.compensations.filter(deleted=None)
|
||||||
|
last_checked = obj.get_last_checked_action()
|
||||||
|
last_checked_tooltip = ""
|
||||||
|
if last_checked:
|
||||||
|
last_checked_tooltip = DATA_CHECKED_PREVIOUSLY_TEMPLATE.format(
|
||||||
|
last_checked.get_timestamp_str_formatted(),
|
||||||
|
last_checked.user
|
||||||
|
)
|
||||||
|
|
||||||
|
has_payment_without_document = obj.payments.exists() and not obj.get_documents()[1].exists()
|
||||||
|
context = {
|
||||||
|
"last_checked": last_checked,
|
||||||
|
"last_checked_tooltip": last_checked_tooltip,
|
||||||
|
"compensations": compensations,
|
||||||
|
"has_payment_without_document": has_payment_without_document,
|
||||||
}
|
}
|
||||||
)
|
return context
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@any_group_check
|
|
||||||
@uuid_required
|
|
||||||
def detail_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a detail view for viewing an intervention's data
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The intervention's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
template = "intervention/detail/view.html"
|
|
||||||
|
|
||||||
# Fetch data, filter out deleted related data
|
|
||||||
intervention = get_object_or_404(
|
|
||||||
Intervention.objects.select_related(
|
|
||||||
"geometry",
|
|
||||||
"legal",
|
|
||||||
"responsible",
|
|
||||||
).prefetch_related(
|
|
||||||
"legal__revocations",
|
|
||||||
),
|
|
||||||
id=id,
|
|
||||||
deleted=None
|
|
||||||
)
|
|
||||||
compensations = intervention.compensations.filter(
|
|
||||||
deleted=None,
|
|
||||||
)
|
|
||||||
_user = request.user
|
|
||||||
is_data_shared = intervention.is_shared_with(user=_user)
|
|
||||||
|
|
||||||
geom_form = SimpleGeomForm(
|
|
||||||
instance=intervention,
|
|
||||||
)
|
|
||||||
last_checked = intervention.get_last_checked_action()
|
|
||||||
last_checked_tooltip = ""
|
|
||||||
if last_checked:
|
|
||||||
last_checked_tooltip = DATA_CHECKED_PREVIOUSLY_TEMPLATE.format(
|
|
||||||
last_checked.get_timestamp_str_formatted(),
|
|
||||||
last_checked.user
|
|
||||||
)
|
|
||||||
|
|
||||||
has_payment_without_document = intervention.payments.exists() and not intervention.get_documents()[1].exists()
|
|
||||||
|
|
||||||
requesting_user_is_only_shared_user = intervention.is_only_shared_with(_user)
|
|
||||||
if requesting_user_is_only_shared_user:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
DO_NOT_FORGET_TO_SHARE
|
|
||||||
)
|
|
||||||
|
|
||||||
context = {
|
|
||||||
"obj": intervention,
|
|
||||||
"last_checked": last_checked,
|
|
||||||
"last_checked_tooltip": last_checked_tooltip,
|
|
||||||
"compensations": compensations,
|
|
||||||
"is_entry_shared": is_data_shared,
|
|
||||||
"geom_form": geom_form,
|
|
||||||
"is_default_member": _user.in_group(DEFAULT_GROUP),
|
|
||||||
"is_zb_member": _user.in_group(ZB_GROUP),
|
|
||||||
"is_ets_member": _user.in_group(ETS_GROUP),
|
|
||||||
"LANIS_LINK": intervention.get_LANIS_link(),
|
|
||||||
"has_payment_without_document": has_payment_without_document,
|
|
||||||
TAB_TITLE_IDENTIFIER: f"{intervention.identifier} - {intervention.title}",
|
|
||||||
}
|
|
||||||
|
|
||||||
request = intervention.set_status_messages(request)
|
|
||||||
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -272,26 +180,6 @@ def edit_view(request: HttpRequest, id: str):
|
|||||||
context = BaseContext(request, context).context
|
context = BaseContext(request, context).context
|
||||||
return render(request, template, context)
|
return render(request, template, context)
|
||||||
|
|
||||||
|
class RemoveInterventionView(LoginRequiredMixin, BaseRemoveModalFormView):
|
||||||
@login_required_modal
|
_MODEL_CLS = Intervention
|
||||||
@login_required
|
_REDIRECT_URL = "intervention:index"
|
||||||
@default_group_required
|
|
||||||
@shared_access_required(Intervention, "id")
|
|
||||||
def remove_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a remove view for this intervention
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The uuid id as string
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = Intervention.objects.get(id=id)
|
|
||||||
identifier = obj.identifier
|
|
||||||
form = RemoveModalForm(request.POST or None, instance=obj, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
_("{} removed").format(identifier),
|
|
||||||
redirect_url=reverse("intervention:index")
|
|
||||||
)
|
|
||||||
|
|||||||
@ -5,19 +5,11 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.decorators import shared_access_required, default_group_required
|
|
||||||
from konova.views.log import AbstractLogView
|
from konova.views.log import AbstractLogView
|
||||||
|
|
||||||
|
|
||||||
class InterventionLogView(AbstractLogView):
|
class InterventionLogView(LoginRequiredMixin, AbstractLogView):
|
||||||
model = Intervention
|
_MODEL_CLS = Intervention
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Intervention, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,19 +5,12 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.decorators import conservation_office_group_required, shared_access_required
|
|
||||||
from konova.views.record import AbstractRecordView
|
from konova.views.record import AbstractRecordView
|
||||||
|
|
||||||
|
|
||||||
class InterventionRecordView(AbstractRecordView):
|
class InterventionRecordView(LoginRequiredMixin, AbstractRecordView):
|
||||||
model = Intervention
|
_MODEL_CLS = Intervention
|
||||||
|
_REDIRECT_URL = "intervention:detail"
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(conservation_office_group_required)
|
|
||||||
@method_decorator(shared_access_required(Intervention, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -5,72 +5,41 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.http import HttpRequest
|
|
||||||
from django.shortcuts import get_object_or_404, render
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.contexts import BaseContext
|
from konova.sub_settings.django_settings import BASE_URL
|
||||||
from konova.decorators import uuid_required
|
from konova.utils.qrcode import QrCode
|
||||||
from konova.forms import SimpleGeomForm
|
from konova.views.report import BaseReportView
|
||||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
|
||||||
from konova.utils.generators import generate_qr_code
|
|
||||||
|
|
||||||
|
|
||||||
@uuid_required
|
class InterventionReportView(BaseReportView):
|
||||||
def report_view(request: HttpRequest, id: str):
|
_TEMPLATE = 'intervention/report/report.html'
|
||||||
""" Renders the public report view
|
_MODEL = Intervention
|
||||||
|
|
||||||
Args:
|
def _get_report_context(self, obj: Intervention):
|
||||||
request (HttpRequest): The incoming request
|
""" Returns the specific context needed for an intervention report
|
||||||
id (str): The id of the intervention
|
|
||||||
|
|
||||||
Returns:
|
Args:
|
||||||
|
obj (Intervention): The object for the report
|
||||||
|
|
||||||
"""
|
Returns:
|
||||||
template = "intervention/report/report.html"
|
dict: The object specific context for rendering the report
|
||||||
intervention = get_object_or_404(Intervention, id=id)
|
"""
|
||||||
|
distinct_deductions = obj.deductions.all().distinct("account")
|
||||||
|
report_url = BASE_URL + reverse("intervention:report", args=(obj.id,))
|
||||||
|
qrcode_report = QrCode(report_url, 10)
|
||||||
|
qrcode_lanis = QrCode(obj.get_LANIS_link(), 7)
|
||||||
|
|
||||||
tab_title = _("Report {}").format(intervention.identifier)
|
return {
|
||||||
# If intervention is not recorded (yet or currently) we need to render another template without any data
|
"deductions": distinct_deductions,
|
||||||
if not intervention.is_ready_for_publish():
|
"qrcode": {
|
||||||
template = "report/unavailable.html"
|
"img": qrcode_report.get_img(),
|
||||||
context = {
|
"url": qrcode_report.get_content(),
|
||||||
TAB_TITLE_IDENTIFIER: tab_title,
|
},
|
||||||
|
"qrcode_lanis": {
|
||||||
|
"img": qrcode_lanis.get_img(),
|
||||||
|
"url": qrcode_lanis.get_content(),
|
||||||
|
},
|
||||||
|
"tables_scrollable": False,
|
||||||
}
|
}
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
# Prepare data for map viewer
|
|
||||||
geom_form = SimpleGeomForm(
|
|
||||||
instance=intervention
|
|
||||||
)
|
|
||||||
parcels = intervention.get_underlying_parcels()
|
|
||||||
|
|
||||||
distinct_deductions = intervention.deductions.all().distinct(
|
|
||||||
"account"
|
|
||||||
)
|
|
||||||
qrcode_url = request.build_absolute_uri(reverse("intervention:report", args=(id,)))
|
|
||||||
qrcode_img = generate_qr_code(qrcode_url, 10)
|
|
||||||
qrcode_lanis_url = intervention.get_LANIS_link()
|
|
||||||
qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7)
|
|
||||||
|
|
||||||
context = {
|
|
||||||
"obj": intervention,
|
|
||||||
"deductions": distinct_deductions,
|
|
||||||
"qrcode": {
|
|
||||||
"img": qrcode_img,
|
|
||||||
"url": qrcode_url,
|
|
||||||
},
|
|
||||||
"qrcode_lanis": {
|
|
||||||
"img": qrcode_img_lanis,
|
|
||||||
"url": qrcode_lanis_url,
|
|
||||||
},
|
|
||||||
"geom_form": geom_form,
|
|
||||||
"parcels": parcels,
|
|
||||||
"tables_scrollable": False,
|
|
||||||
TAB_TITLE_IDENTIFIER: tab_title,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|||||||
@ -5,22 +5,12 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
from intervention.forms.modals.resubmission import InterventionResubmissionModalForm
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.decorators import default_group_required, shared_access_required, login_required_modal
|
|
||||||
from konova.views.resubmission import AbstractResubmissionView
|
from konova.views.resubmission import AbstractResubmissionView
|
||||||
|
|
||||||
|
|
||||||
class InterventionResubmissionView(AbstractResubmissionView):
|
class InterventionResubmissionView(AbstractResubmissionView):
|
||||||
model = Intervention
|
_MODEL_CLS = Intervention
|
||||||
redirect_url_base = "intervention:detail"
|
_FORM_CLS = InterventionResubmissionModalForm
|
||||||
form_action_url_base = "intervention:resubmission-create"
|
_REDIRECT_URL = "intervention:detail"
|
||||||
|
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Intervention, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|||||||
@ -6,113 +6,71 @@ Created on: 19.08.22
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
from intervention.forms.modals.revocation import NewRevocationModalForm, EditRevocationModalForm, \
|
from intervention.forms.modals.revocation import NewRevocationModalForm, EditRevocationModalForm, \
|
||||||
RemoveRevocationModalForm
|
RemoveRevocationModalForm
|
||||||
from intervention.models import Intervention, RevocationDocument, Revocation
|
from intervention.models import Intervention, RevocationDocument
|
||||||
from konova.decorators import default_group_required, shared_access_required, login_required_modal
|
|
||||||
from konova.utils.documents import get_document
|
from konova.utils.documents import get_document
|
||||||
from konova.utils.message_templates import REVOCATION_ADDED, DATA_UNSHARED, REVOCATION_EDITED, REVOCATION_REMOVED
|
from konova.utils.message_templates import DATA_UNSHARED, REVOCATION_EDITED, REVOCATION_REMOVED, REVOCATION_ADDED
|
||||||
|
from konova.views.base import BaseModalFormView, BaseView
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class BaseRevocationView(LoginRequiredMixin, BaseModalFormView):
|
||||||
@default_group_required
|
_MODEL_CLS = Intervention
|
||||||
@shared_access_required(Intervention, "id")
|
_REDIRECT_URL = "intervention:detail"
|
||||||
def new_revocation_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders sharing form for an intervention
|
|
||||||
|
|
||||||
Args:
|
class Meta:
|
||||||
request (HttpRequest): The incoming request
|
abstract = True
|
||||||
id (str): Intervention's id
|
|
||||||
|
|
||||||
Returns:
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
"""
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
intervention = get_object_or_404(Intervention, id=id)
|
url = super()._get_redirect_url(*args, **kwargs)
|
||||||
form = NewRevocationModalForm(request.POST or None, request.FILES or None, instance=intervention, request=request)
|
return f"{url}#related_data"
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=REVOCATION_ADDED,
|
|
||||||
redirect_url=reverse("intervention:detail", args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class NewRevocationView(BaseRevocationView):
|
||||||
@default_group_required
|
_FORM_CLS = NewRevocationModalForm
|
||||||
def get_revocation_view(request: HttpRequest, doc_id: str):
|
_MSG_SUCCESS = REVOCATION_ADDED
|
||||||
""" Returns the revocation document as downloadable file
|
|
||||||
|
|
||||||
Wraps the generic document fetcher function from konova.utils.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
doc_id (str): The document id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
doc = get_object_or_404(RevocationDocument, id=doc_id)
|
|
||||||
# File download only possible if related instance is shared with user
|
|
||||||
if not doc.instance.legal.intervention.users.filter(id=request.user.id):
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
DATA_UNSHARED
|
|
||||||
)
|
|
||||||
return redirect("intervention:detail", id=doc.instance.id)
|
|
||||||
return get_document(doc)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class EditRevocationView(BaseRevocationView):
|
||||||
@default_group_required
|
_FORM_CLS = EditRevocationModalForm
|
||||||
@shared_access_required(Intervention, "id")
|
_MSG_SUCCESS = REVOCATION_EDITED
|
||||||
def edit_revocation_view(request: HttpRequest, id: str, revocation_id: str):
|
|
||||||
""" Renders a edit view for a revocation
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The intervention's id as string
|
|
||||||
revocation_id (str): The revocation's id as string
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
intervention = get_object_or_404(Intervention, id=id)
|
|
||||||
revocation = get_object_or_404(Revocation, id=revocation_id)
|
|
||||||
|
|
||||||
form = EditRevocationModalForm(request.POST or None, request.FILES or None, instance=intervention, revocation=revocation, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
REVOCATION_EDITED,
|
|
||||||
redirect_url=reverse("intervention:detail", args=(intervention.id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required_modal
|
class RemoveRevocationView(BaseRevocationView):
|
||||||
@login_required
|
_FORM_CLS = RemoveRevocationModalForm
|
||||||
@default_group_required
|
_MSG_SUCCESS = REVOCATION_REMOVED
|
||||||
@shared_access_required(Intervention, "id")
|
|
||||||
def remove_revocation_view(request: HttpRequest, id: str, revocation_id: str):
|
|
||||||
""" Renders a remove view for a revocation
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The intervention's id as string
|
|
||||||
revocation_id (str): The revocation's id as string
|
|
||||||
|
|
||||||
Returns:
|
class GetRevocationDocumentView(LoginRequiredMixin, BaseView):
|
||||||
|
_MODEL_CLS = RevocationDocument
|
||||||
|
_REDIRECT_URL = "intervention:detail"
|
||||||
|
|
||||||
"""
|
def get(self, request: HttpRequest, doc_id: str):
|
||||||
intervention = get_object_or_404(Intervention, id=id)
|
doc = get_object_or_404(RevocationDocument, id=doc_id)
|
||||||
revocation = get_object_or_404(Revocation, id=revocation_id)
|
# File download only possible if related instance is shared with user
|
||||||
|
if not doc.instance.legal.intervention.users.filter(id=request.user.id):
|
||||||
|
messages.info(
|
||||||
|
request,
|
||||||
|
DATA_UNSHARED
|
||||||
|
)
|
||||||
|
return redirect("intervention:detail", id=doc.instance.id)
|
||||||
|
return get_document(doc)
|
||||||
|
|
||||||
form = RemoveRevocationModalForm(request.POST or None, instance=intervention, revocation=revocation, request=request)
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return form.process_request(
|
return user.is_default_user()
|
||||||
request,
|
|
||||||
REVOCATION_REMOVED,
|
|
||||||
redirect_url=reverse("intervention:detail", args=(intervention.id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
obj = get_object_or_404(self._MODEL_CLS, id=kwargs.get("doc_id"))
|
||||||
|
assert obj is not None
|
||||||
|
return obj.instance.intervention.is_shared_with(user)
|
||||||
|
|
||||||
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
url = super()._get_redirect_url(*args, **kwargs)
|
||||||
|
return f"{url}#related_data"
|
||||||
|
|||||||
@ -5,29 +5,15 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.decorators import default_group_required, shared_access_required, login_required_modal
|
|
||||||
from konova.views.share import AbstractShareByTokenView, AbstractShareFormView
|
from konova.views.share import AbstractShareByTokenView, AbstractShareFormView
|
||||||
|
|
||||||
|
|
||||||
class InterventionShareByTokenView(AbstractShareByTokenView):
|
class InterventionShareByTokenView(AbstractShareByTokenView):
|
||||||
model = Intervention
|
_MODEL_CLS = Intervention
|
||||||
redirect_url = "intervention:detail"
|
_REDIRECT_URL = "intervention:detail"
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class InterventionShareFormView(AbstractShareFormView):
|
class InterventionShareFormView(AbstractShareFormView):
|
||||||
model = Intervention
|
_MODEL_CLS = Intervention
|
||||||
|
_REDIRECT_URL = "intervention:detail"
|
||||||
@method_decorator(login_required_modal)
|
|
||||||
@method_decorator(login_required)
|
|
||||||
@method_decorator(default_group_required)
|
|
||||||
@method_decorator(shared_access_required(Intervention, "id"))
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
@ -10,21 +10,18 @@ from abc import abstractmethod
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from compensation.models import EcoAccount
|
|
||||||
from konova.models import BaseObject
|
|
||||||
|
|
||||||
|
|
||||||
class BaseForm(forms.Form):
|
class BaseForm(forms.Form):
|
||||||
"""
|
"""
|
||||||
Basic form for that holds attributes needed in all other forms
|
Basic form for that holds attributes needed in all other forms
|
||||||
"""
|
"""
|
||||||
template = None
|
|
||||||
action_url = None
|
action_url = None
|
||||||
action_btn_label = _("Save")
|
action_btn_label = _("Save")
|
||||||
form_title = None
|
form_title = None
|
||||||
cancel_redirect = None
|
cancel_redirect = None
|
||||||
form_caption = None
|
form_caption = None
|
||||||
instance = None # The data holding model object
|
instance = None # The data holding model object
|
||||||
|
user = None # The performing user
|
||||||
request = None
|
request = None
|
||||||
form_attrs = {} # Holds additional attributes, that can be used in the template
|
form_attrs = {} # Holds additional attributes, that can be used in the template
|
||||||
has_required_fields = False # Automatically set. Triggers hint rendering in templates
|
has_required_fields = False # Automatically set. Triggers hint rendering in templates
|
||||||
@ -33,6 +30,7 @@ class BaseForm(forms.Form):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.instance = kwargs.pop("instance", None)
|
self.instance = kwargs.pop("instance", None)
|
||||||
|
self.user = kwargs.pop("user", None)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if self.request is not None:
|
if self.request is not None:
|
||||||
self.user = self.request.user
|
self.user = self.request.user
|
||||||
@ -42,11 +40,10 @@ class BaseForm(forms.Form):
|
|||||||
self.has_required_fields = True
|
self.has_required_fields = True
|
||||||
break
|
break
|
||||||
|
|
||||||
self.check_for_recorded_instance()
|
|
||||||
self.__check_valid_label_input_ratio()
|
self.__check_valid_label_input_ratio()
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def save(self):
|
def save(self, *arg, **kwargs):
|
||||||
# To be implemented in subclasses!
|
# To be implemented in subclasses!
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -136,34 +133,3 @@ class BaseForm(forms.Form):
|
|||||||
set_class = self.fields[field].widget.attrs.get("class", "")
|
set_class = self.fields[field].widget.attrs.get("class", "")
|
||||||
set_class = set_class.replace(cls, "")
|
set_class = set_class.replace(cls, "")
|
||||||
self.fields[field].widget.attrs["class"] = set_class
|
self.fields[field].widget.attrs["class"] = set_class
|
||||||
|
|
||||||
def check_for_recorded_instance(self):
|
|
||||||
""" Checks if the instance is recorded and runs some special logic if yes
|
|
||||||
|
|
||||||
If the instance is recorded, the form shall not display any possibility to
|
|
||||||
edit any data. Instead, the users should get some information about why they can not edit anything.
|
|
||||||
|
|
||||||
There are situations where the form should be rendered regularly,
|
|
||||||
e.g deduction forms for (recorded) eco accounts.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
is_none = self.instance is None
|
|
||||||
is_other_data_type = not isinstance(self.instance, BaseObject)
|
|
||||||
|
|
||||||
if is_none or is_other_data_type:
|
|
||||||
# Do nothing
|
|
||||||
return
|
|
||||||
|
|
||||||
if self.instance.is_recorded:
|
|
||||||
self.block_form()
|
|
||||||
|
|
||||||
def block_form(self):
|
|
||||||
"""
|
|
||||||
Overwrites template, providing no actions
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.template = "form/recorded_no_edit.html"
|
|
||||||
@ -23,7 +23,7 @@ class BaseModalForm(BaseForm, BSModalForm):
|
|||||||
"""
|
"""
|
||||||
is_modal_form = True
|
is_modal_form = True
|
||||||
render_submit = True
|
render_submit = True
|
||||||
template = "modal/modal_form.html"
|
_TEMPLATE = "modal/modal_form.html"
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
@ -43,7 +43,7 @@ class BaseModalForm(BaseForm, BSModalForm):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
redirect_url = redirect_url if redirect_url is not None else request.META.get("HTTP_REFERER", "home")
|
redirect_url = redirect_url if redirect_url is not None else request.META.get("HTTP_REFERER", "home")
|
||||||
template = self.template
|
template = self._TEMPLATE
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if self.is_valid():
|
if self.is_valid():
|
||||||
if not is_ajax(request.META):
|
if not is_ajax(request.META):
|
||||||
|
|||||||
@ -8,10 +8,10 @@ Created on: 15.08.22
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models.fields.files import FieldFile
|
from django.db.models.fields.files import FieldFile
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from konova.forms.modals.base_form import BaseModalForm
|
from konova.forms.modals.base_form import BaseModalForm
|
||||||
from konova.models import AbstractDocument
|
|
||||||
from konova.utils import validators
|
from konova.utils import validators
|
||||||
from konova.utils.message_templates import DOCUMENT_EDITED, FILE_SIZE_TOO_LARGE, FILE_TYPE_UNSUPPORTED
|
from konova.utils.message_templates import DOCUMENT_EDITED, FILE_SIZE_TOO_LARGE, FILE_TYPE_UNSUPPORTED
|
||||||
from user.models import UserActionLogEntry
|
from user.models import UserActionLogEntry
|
||||||
@ -69,7 +69,7 @@ class NewDocumentModalForm(BaseModalForm):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
document_model = None
|
_DOCUMENT_CLS = None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
@ -81,7 +81,7 @@ class NewDocumentModalForm(BaseModalForm):
|
|||||||
self.form_attrs = {
|
self.form_attrs = {
|
||||||
"enctype": "multipart/form-data", # important for file upload
|
"enctype": "multipart/form-data", # important for file upload
|
||||||
}
|
}
|
||||||
if not self.document_model:
|
if not self._DOCUMENT_CLS:
|
||||||
raise NotImplementedError("Unsupported document type for {}".format(self.instance.__class__))
|
raise NotImplementedError("Unsupported document type for {}".format(self.instance.__class__))
|
||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
@ -93,14 +93,14 @@ class NewDocumentModalForm(BaseModalForm):
|
|||||||
# FieldFile declares that no new file has been uploaded and we do not need to check on the file again
|
# FieldFile declares that no new file has been uploaded and we do not need to check on the file again
|
||||||
return super_valid
|
return super_valid
|
||||||
|
|
||||||
mime_type_valid = self.document_model.is_mime_type_valid(_file)
|
mime_type_valid = self._DOCUMENT_CLS.is_mime_type_valid(_file)
|
||||||
if not mime_type_valid:
|
if not mime_type_valid:
|
||||||
self.add_error(
|
self.add_error(
|
||||||
"file",
|
"file",
|
||||||
FILE_TYPE_UNSUPPORTED
|
FILE_TYPE_UNSUPPORTED
|
||||||
)
|
)
|
||||||
|
|
||||||
file_size_valid = self.document_model.is_file_size_valid(_file)
|
file_size_valid = self._DOCUMENT_CLS.is_file_size_valid(_file)
|
||||||
if not file_size_valid:
|
if not file_size_valid:
|
||||||
self.add_error(
|
self.add_error(
|
||||||
"file",
|
"file",
|
||||||
@ -115,7 +115,7 @@ class NewDocumentModalForm(BaseModalForm):
|
|||||||
action = UserActionLogEntry.get_created_action(self.user)
|
action = UserActionLogEntry.get_created_action(self.user)
|
||||||
edited_action = UserActionLogEntry.get_edited_action(self.user, _("Added document"))
|
edited_action = UserActionLogEntry.get_edited_action(self.user, _("Added document"))
|
||||||
|
|
||||||
doc = self.document_model.objects.create(
|
doc = self._DOCUMENT_CLS.objects.create(
|
||||||
created=action,
|
created=action,
|
||||||
title=self.cleaned_data["title"],
|
title=self.cleaned_data["title"],
|
||||||
comment=self.cleaned_data["comment"],
|
comment=self.cleaned_data["comment"],
|
||||||
@ -133,10 +133,12 @@ class NewDocumentModalForm(BaseModalForm):
|
|||||||
|
|
||||||
class EditDocumentModalForm(NewDocumentModalForm):
|
class EditDocumentModalForm(NewDocumentModalForm):
|
||||||
document = None
|
document = None
|
||||||
document_model = AbstractDocument
|
_DOCUMENT_CLS = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.document = kwargs.pop("document", None)
|
doc_id = kwargs.pop("doc_id", None)
|
||||||
|
self.document = get_object_or_404(self._DOCUMENT_CLS, id=doc_id)
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.form_title = _("Edit document")
|
self.form_title = _("Edit document")
|
||||||
form_data = {
|
form_data = {
|
||||||
|
|||||||
@ -6,10 +6,11 @@ Created on: 15.08.22
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from konova.forms.modals.base_form import BaseModalForm
|
from konova.forms.modals.base_form import BaseModalForm
|
||||||
from konova.models import BaseObject
|
from konova.models import BaseObject, Deadline
|
||||||
|
|
||||||
|
|
||||||
class RemoveModalForm(BaseModalForm):
|
class RemoveModalForm(BaseModalForm):
|
||||||
@ -51,9 +52,19 @@ class RemoveDeadlineModalForm(RemoveModalForm):
|
|||||||
deadline = None
|
deadline = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
deadline = kwargs.pop("deadline", None)
|
deadline_id = kwargs.pop("deadline_id", None)
|
||||||
self.deadline = deadline
|
self.deadline = get_object_or_404(Deadline, id=deadline_id)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
self.instance.remove_deadline(self)
|
self.instance.remove_deadline(self)
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveDocumentModalForm(RemoveModalForm):
|
||||||
|
instance = None
|
||||||
|
_DOCUMENT_CLS = None
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
document_id = kwargs.pop("doc_id", None)
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.instance = get_object_or_404(self._DOCUMENT_CLS, id=document_id)
|
||||||
|
|||||||
@ -291,5 +291,5 @@ Overwrites netgis.css attributes
|
|||||||
}
|
}
|
||||||
|
|
||||||
.netgis-menu{
|
.netgis-menu{
|
||||||
z-index: 1 !important;
|
z-index: 100 !important;
|
||||||
}
|
}
|
||||||
@ -543,7 +543,7 @@ class BaseViewTestCase(BaseTestCase):
|
|||||||
for url, redirect_to in urls.items():
|
for url, redirect_to in urls.items():
|
||||||
response = client.get(url, follow=True)
|
response = client.get(url, follow=True)
|
||||||
# Expect redirects to the landing page
|
# Expect redirects to the landing page
|
||||||
self.assertEqual(response.redirect_chain[0], (redirect_to, 302), msg=f"Failed for {url}")
|
self.assertEqual(response.redirect_chain[0], (redirect_to, 302), msg=f"Failed for {url}. Expected {redirect_to}")
|
||||||
|
|
||||||
def assert_url_fail(self, client: Client, urls: list):
|
def assert_url_fail(self, client: Client, urls: list):
|
||||||
""" Assert for all given urls a direct 302 response
|
""" Assert for all given urls a direct 302 response
|
||||||
|
|||||||
@ -103,7 +103,7 @@ class EditDeadlineModalFormTestCase(NewDeadlineModalFormTestCase):
|
|||||||
data,
|
data,
|
||||||
request=self.request,
|
request=self.request,
|
||||||
instance=self.compensation,
|
instance=self.compensation,
|
||||||
deadline=self.finished_deadline,
|
deadline_id=self.finished_deadline.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertTrue(form.is_valid(), msg=form.errors)
|
self.assertTrue(form.is_valid(), msg=form.errors)
|
||||||
|
|||||||
@ -17,9 +17,9 @@ from django.utils.timezone import now
|
|||||||
from compensation.forms.modals.document import NewEcoAccountDocumentModalForm, NewCompensationDocumentModalForm
|
from compensation.forms.modals.document import NewEcoAccountDocumentModalForm, NewCompensationDocumentModalForm
|
||||||
from compensation.models import Payment
|
from compensation.models import Payment
|
||||||
from ema.forms import NewEmaDocumentModalForm
|
from ema.forms import NewEmaDocumentModalForm
|
||||||
from intervention.forms.modals.document import NewInterventionDocumentModalForm
|
from intervention.forms.modals.document import NewInterventionDocumentModalForm, EditInterventionDocumentModalForm
|
||||||
from intervention.models import InterventionDocument
|
from intervention.models import InterventionDocument
|
||||||
from konova.forms.modals import EditDocumentModalForm, NewDocumentModalForm, RecordModalForm, RemoveModalForm, \
|
from konova.forms.modals import NewDocumentModalForm, RecordModalForm, RemoveModalForm, \
|
||||||
RemoveDeadlineModalForm, ResubmissionModalForm
|
RemoveDeadlineModalForm, ResubmissionModalForm
|
||||||
from konova.models import Resubmission
|
from konova.models import Resubmission
|
||||||
from konova.tests.test_views import BaseTestCase
|
from konova.tests.test_views import BaseTestCase
|
||||||
@ -106,12 +106,12 @@ class EditDocumentModalFormTestCase(NewDocumentModalFormTestCase):
|
|||||||
InterventionDocument,
|
InterventionDocument,
|
||||||
instance=self.intervention
|
instance=self.intervention
|
||||||
)
|
)
|
||||||
self.form = EditDocumentModalForm(
|
self.form = EditInterventionDocumentModalForm(
|
||||||
self.data,
|
self.data,
|
||||||
dummy_file_dict,
|
dummy_file_dict,
|
||||||
request=self.request,
|
request=self.request,
|
||||||
instance=self.intervention,
|
instance=self.intervention,
|
||||||
document=self.doc
|
doc_id=self.doc.id
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
@ -122,7 +122,6 @@ class EditDocumentModalFormTestCase(NewDocumentModalFormTestCase):
|
|||||||
self.assertEqual(self.form.fields["title"].initial, self.doc.title)
|
self.assertEqual(self.form.fields["title"].initial, self.doc.title)
|
||||||
self.assertEqual(self.form.fields["comment"].initial, self.doc.comment)
|
self.assertEqual(self.form.fields["comment"].initial, self.doc.comment)
|
||||||
self.assertEqual(self.form.fields["creation_date"].initial, self.doc.date_of_creation)
|
self.assertEqual(self.form.fields["creation_date"].initial, self.doc.date_of_creation)
|
||||||
self.assertEqual(self.form.fields["file"].initial, self.doc.file)
|
|
||||||
|
|
||||||
def test_save(self):
|
def test_save(self):
|
||||||
self.assertTrue(self.form.is_valid(), msg=self.form.errors)
|
self.assertTrue(self.form.is_valid(), msg=self.form.errors)
|
||||||
@ -256,7 +255,7 @@ class RemoveDeadlineTestCase(BaseTestCase):
|
|||||||
form = RemoveDeadlineModalForm(
|
form = RemoveDeadlineModalForm(
|
||||||
request=self.request,
|
request=self.request,
|
||||||
instance=self.compensation,
|
instance=self.compensation,
|
||||||
deadline=self.finished_deadline
|
deadline_id=self.finished_deadline.id
|
||||||
)
|
)
|
||||||
self.assertEqual(form.form_title, str(_("Remove")))
|
self.assertEqual(form.form_title, str(_("Remove")))
|
||||||
self.assertEqual(form.form_caption, str(_("Are you sure?")))
|
self.assertEqual(form.form_caption, str(_("Are you sure?")))
|
||||||
@ -273,7 +272,7 @@ class RemoveDeadlineTestCase(BaseTestCase):
|
|||||||
data,
|
data,
|
||||||
request=self.request,
|
request=self.request,
|
||||||
instance=self.compensation,
|
instance=self.compensation,
|
||||||
deadline=self.finished_deadline
|
deadline_id=self.finished_deadline.id
|
||||||
)
|
)
|
||||||
self.assertTrue(form.is_valid(), msg=form.errors)
|
self.assertTrue(form.is_valid(), msg=form.errors)
|
||||||
form.save()
|
form.save()
|
||||||
|
|||||||
@ -7,9 +7,7 @@ Created on: 01.09.21
|
|||||||
"""
|
"""
|
||||||
from django.http import FileResponse, HttpRequest, Http404
|
from django.http import FileResponse, HttpRequest, Http404
|
||||||
|
|
||||||
from konova.forms.modals import RemoveModalForm
|
|
||||||
from konova.models import AbstractDocument
|
from konova.models import AbstractDocument
|
||||||
from konova.utils.message_templates import DOCUMENT_REMOVED_TEMPLATE
|
|
||||||
|
|
||||||
|
|
||||||
def get_document(doc: AbstractDocument):
|
def get_document(doc: AbstractDocument):
|
||||||
@ -26,28 +24,3 @@ def get_document(doc: AbstractDocument):
|
|||||||
return FileResponse(doc.file, as_attachment=True)
|
return FileResponse(doc.file, as_attachment=True)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
raise Http404()
|
raise Http404()
|
||||||
|
|
||||||
|
|
||||||
def remove_document(request: HttpRequest, doc: AbstractDocument):
|
|
||||||
""" Renders a form for uploading new documents
|
|
||||||
|
|
||||||
This function works using a modal. We are not using the regular way, the django bootstrap modal forms are
|
|
||||||
intended to be used. Instead of View classes we work using the classic way of dealing with forms (see below).
|
|
||||||
It is important to mention, that modal forms, which should reload the page afterwards, must provide a
|
|
||||||
'reload_page' bool in the context. This way, the modal may reload the page or not.
|
|
||||||
|
|
||||||
For further details see the comments in templates/modal or
|
|
||||||
https://github.com/trco/django-bootstrap-modal-forms
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
title = doc.title
|
|
||||||
form = RemoveModalForm(request.POST or None, instance=doc, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request=request,
|
|
||||||
msg_success=DOCUMENT_REMOVED_TEMPLATE.format(title),
|
|
||||||
)
|
|
||||||
@ -5,6 +5,11 @@ Contact: michel.peltriaux@sgdnord.rlp.de
|
|||||||
Created on: 17.09.21
|
Created on: 17.09.21
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.http import HttpRequest, Http404
|
||||||
|
|
||||||
|
|
||||||
def format_german_float(num) -> str:
|
def format_german_float(num) -> str:
|
||||||
@ -19,3 +24,27 @@ def format_german_float(num) -> str:
|
|||||||
num (str): The number as german Gleitkommazahl
|
num (str): The number as german Gleitkommazahl
|
||||||
"""
|
"""
|
||||||
return format(num, "0,.2f").replace(",", "X").replace(".", ",").replace("X", ".")
|
return format(num, "0,.2f").replace(",", "X").replace(".", ",").replace("X", ".")
|
||||||
|
|
||||||
|
|
||||||
|
def check_user_is_in_any_group(request: HttpRequest):
|
||||||
|
"""
|
||||||
|
Checks for any group membership. Adds a message in case of having none.
|
||||||
|
|
||||||
|
"""
|
||||||
|
user = request.user
|
||||||
|
# Inform user about missing group privileges!
|
||||||
|
groups = user.groups.all()
|
||||||
|
if not groups:
|
||||||
|
messages.info(
|
||||||
|
request,
|
||||||
|
_("+++ Attention: You are not part of any group. You won't be able to create, edit or do anything. Please contact an administrator. +++")
|
||||||
|
)
|
||||||
|
return request
|
||||||
|
|
||||||
|
def check_id_is_valid_uuid(uuid: str):
|
||||||
|
if uuid:
|
||||||
|
try:
|
||||||
|
# Check whether the id is a proper uuid or something that would break a db fetch
|
||||||
|
UUID(uuid)
|
||||||
|
except ValueError:
|
||||||
|
raise Http404
|
||||||
|
|||||||
@ -7,10 +7,6 @@ Created on: 09.11.20
|
|||||||
"""
|
"""
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
import qrcode
|
|
||||||
import qrcode.image.svg
|
|
||||||
|
|
||||||
from io import BytesIO
|
|
||||||
|
|
||||||
|
|
||||||
def generate_token() -> str:
|
def generate_token() -> str:
|
||||||
@ -42,23 +38,3 @@ def generate_random_string(length: int, use_numbers: bool = False, use_letters_l
|
|||||||
ret_val = "".join(random.choice(elements) for i in range(length))
|
ret_val = "".join(random.choice(elements) for i in range(length))
|
||||||
return ret_val
|
return ret_val
|
||||||
|
|
||||||
|
|
||||||
def generate_qr_code(content: str, size: int = 20) -> str:
|
|
||||||
""" Generates a qr code from given content
|
|
||||||
|
|
||||||
Args:
|
|
||||||
content (str): The content for the qr code
|
|
||||||
size (int): The image size
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
qrcode_svg (str): The qr code as svg
|
|
||||||
"""
|
|
||||||
qrcode_factory = qrcode.image.svg.SvgImage
|
|
||||||
qrcode_img = qrcode.make(
|
|
||||||
content,
|
|
||||||
image_factory=qrcode_factory,
|
|
||||||
box_size=size
|
|
||||||
)
|
|
||||||
stream = BytesIO()
|
|
||||||
qrcode_img.save(stream)
|
|
||||||
return stream.getvalue().decode()
|
|
||||||
|
|||||||
@ -19,7 +19,20 @@ IDENTIFIER_REPLACED = _("The identifier '{}' had to be changed to '{}' since ano
|
|||||||
ENTRY_REMOVE_MISSING_PERMISSION = _("Only conservation or registration office users are allowed to remove entries.")
|
ENTRY_REMOVE_MISSING_PERMISSION = _("Only conservation or registration office users are allowed to remove entries.")
|
||||||
MISSING_GROUP_PERMISSION = _("You need to be part of another user group.")
|
MISSING_GROUP_PERMISSION = _("You need to be part of another user group.")
|
||||||
CHECK_STATE_RESET = _("Status of Checked reset")
|
CHECK_STATE_RESET = _("Status of Checked reset")
|
||||||
|
|
||||||
|
# USER | TEAM
|
||||||
|
TEAM_ADDED = _("New team added")
|
||||||
|
TEAM_EDITED = _("Team edited")
|
||||||
|
TEAM_REMOVED = _("Team removed")
|
||||||
|
TEAM_LEFT = _("Left Team")
|
||||||
|
|
||||||
|
# REMOVED
|
||||||
|
GENERIC_REMOVED_TEMPLATE = _("{} removed")
|
||||||
|
|
||||||
|
# RECORDING
|
||||||
RECORDED_BLOCKS_EDIT = _("Entry is recorded. To edit data, the entry first needs to be unrecorded.")
|
RECORDED_BLOCKS_EDIT = _("Entry is recorded. To edit data, the entry first needs to be unrecorded.")
|
||||||
|
ENTRY_RECORDED = _("{} recorded")
|
||||||
|
ENTRY_UNRECORDED = _("{} unrecorded")
|
||||||
|
|
||||||
# SHARE
|
# SHARE
|
||||||
DATA_UNSHARED = _("This data is not shared with you")
|
DATA_UNSHARED = _("This data is not shared with you")
|
||||||
@ -95,3 +108,6 @@ DATA_IS_UNCHECKED = _("Current data not checked yet")
|
|||||||
|
|
||||||
# API TOKEN SETTINGS
|
# API TOKEN SETTINGS
|
||||||
NEW_API_TOKEN_GENERATED = _("New token generated. Administrators need to validate.")
|
NEW_API_TOKEN_GENERATED = _("New token generated. Administrators need to validate.")
|
||||||
|
|
||||||
|
# RESUBMISSION
|
||||||
|
NEW_RESUBMISSION_CREATED = _("Resubmission set")
|
||||||
|
|||||||
47
konova/utils/qrcode.py
Normal file
47
konova/utils/qrcode.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
"""
|
||||||
|
Author: Michel Peltriaux
|
||||||
|
Created on: 17.10.25
|
||||||
|
|
||||||
|
"""
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
import qrcode
|
||||||
|
import qrcode.image.svg as svg
|
||||||
|
|
||||||
|
|
||||||
|
class QrCode:
|
||||||
|
""" A wrapping class for creating a qr code with content
|
||||||
|
|
||||||
|
"""
|
||||||
|
_content = None
|
||||||
|
_img = None
|
||||||
|
|
||||||
|
def __init__(self, content: str, size: int):
|
||||||
|
self._content = content
|
||||||
|
self._img = self._generate_qr_code(content, size)
|
||||||
|
|
||||||
|
def _generate_qr_code(self, content: str, size: int = 20) -> str:
|
||||||
|
""" Generates a qr code from given content
|
||||||
|
|
||||||
|
Args:
|
||||||
|
content (str): The content for the qr code
|
||||||
|
size (int): The image size
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
qrcode_svg (str): The qr code as svg
|
||||||
|
"""
|
||||||
|
img_factory = svg.SvgImage
|
||||||
|
qrcode_img = qrcode.make(
|
||||||
|
content,
|
||||||
|
image_factory=img_factory,
|
||||||
|
box_size=size
|
||||||
|
)
|
||||||
|
stream = BytesIO()
|
||||||
|
qrcode_img.save(stream)
|
||||||
|
return stream.getvalue().decode()
|
||||||
|
|
||||||
|
def get_img(self):
|
||||||
|
return self._img
|
||||||
|
|
||||||
|
def get_content(self):
|
||||||
|
return self._content
|
||||||
@ -5,104 +5,47 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 22.08.22
|
Created on: 22.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.shortcuts import get_object_or_404
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.urls import reverse
|
|
||||||
from django.views import View
|
|
||||||
|
|
||||||
from compensation.forms.modals.compensation_action import NewCompensationActionModalForm, \
|
from compensation.forms.modals.compensation_action import NewCompensationActionModalForm, \
|
||||||
EditCompensationActionModalForm, RemoveCompensationActionModalForm
|
EditCompensationActionModalForm, RemoveCompensationActionModalForm
|
||||||
from compensation.models import CompensationAction
|
|
||||||
from konova.utils.message_templates import COMPENSATION_STATE_ADDED, COMPENSATION_STATE_EDITED, \
|
from konova.utils.message_templates import COMPENSATION_STATE_ADDED, COMPENSATION_STATE_EDITED, \
|
||||||
COMPENSATION_STATE_REMOVED
|
COMPENSATION_STATE_REMOVED
|
||||||
|
from konova.views.base import BaseModalFormView
|
||||||
|
|
||||||
|
|
||||||
class AbstractCompensationActionView(View):
|
class AbstractCompensationActionView(LoginRequiredMixin, BaseModalFormView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
redirect_url = None
|
_REDIRECT_URL = None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
|
|
||||||
class AbstractNewCompensationActionView(AbstractCompensationActionView):
|
class AbstractNewCompensationActionView(AbstractCompensationActionView):
|
||||||
|
_FORM_CLS = NewCompensationActionModalForm
|
||||||
|
_MSG_SUCCESS = COMPENSATION_STATE_ADDED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str):
|
|
||||||
""" Renders a form for adding new actions
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The object's id to which the new action will be related
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
form = NewCompensationActionModalForm(request.POST or None, instance=obj, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=COMPENSATION_STATE_ADDED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str):
|
|
||||||
return self.get(request, id)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractEditCompensationActionView(AbstractCompensationActionView):
|
class AbstractEditCompensationActionView(AbstractCompensationActionView):
|
||||||
|
_FORM_CLS = EditCompensationActionModalForm
|
||||||
|
_MSG_SUCCESS = COMPENSATION_STATE_EDITED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str, action_id: str):
|
|
||||||
""" Renders a form for editing a action
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The object id
|
|
||||||
action_id (str): The action's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
action = get_object_or_404(CompensationAction, id=action_id)
|
|
||||||
form = EditCompensationActionModalForm(request.POST or None, instance=obj, action=action, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=COMPENSATION_STATE_EDITED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str, action_id: str):
|
|
||||||
return self.get(request, id, action_id)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractRemoveCompensationActionView(AbstractCompensationActionView):
|
class AbstractRemoveCompensationActionView(AbstractCompensationActionView):
|
||||||
|
_FORM_CLS = RemoveCompensationActionModalForm
|
||||||
|
_MSG_SUCCESS = COMPENSATION_STATE_REMOVED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str, action_id: str):
|
|
||||||
""" Renders a form for removing aaction
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The object id
|
|
||||||
action_id (str): The action's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
action = get_object_or_404(CompensationAction, id=action_id)
|
|
||||||
form = RemoveCompensationActionModalForm(request.POST or None, instance=obj, action=action, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=COMPENSATION_STATE_REMOVED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str, action_id: str):
|
|
||||||
return self.get(request, id, action_id)
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
641
konova/views/base.py
Normal file
641
konova/views/base.py
Normal file
@ -0,0 +1,641 @@
|
|||||||
|
"""
|
||||||
|
Author: Michel Peltriaux
|
||||||
|
Created on: 15.10.25
|
||||||
|
|
||||||
|
"""
|
||||||
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
from bootstrap_modal_forms.mixins import is_ajax
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.http import HttpRequest, JsonResponse, HttpResponseRedirect
|
||||||
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.views import View
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from konova.contexts import BaseContext
|
||||||
|
from konova.forms import BaseForm, SimpleGeomForm
|
||||||
|
from konova.models import BaseObject
|
||||||
|
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
||||||
|
from konova.utils.general import check_user_is_in_any_group
|
||||||
|
from konova.utils.message_templates import MISSING_GROUP_PERMISSION, DATA_UNSHARED, IDENTIFIER_REPLACED, \
|
||||||
|
GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE, RECORDED_BLOCKS_EDIT, FORM_INVALID
|
||||||
|
|
||||||
|
|
||||||
|
class BaseView(View):
|
||||||
|
""" An abstract base view
|
||||||
|
|
||||||
|
This class represents the root of all views on this project. It defines private variables which have to be used
|
||||||
|
by inheriting classes for proper generic inheriting.
|
||||||
|
|
||||||
|
"""
|
||||||
|
_TEMPLATE: str = "CHANGE_ME" # Path to template file
|
||||||
|
_TAB_TITLE: str = "CHANGE_ME" # Title displayed on browser tab
|
||||||
|
_REDIRECT_URL: str = "CHANGE_ME" # Default URL to redirect after processing (notation as django url "namespace:endpoint")
|
||||||
|
_REDIRECT_URL_ERROR: str = "home" # Default URL to redirect in case of an error (same notation)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
""" Dispatching requests before forwarding them into GET or POST endpoints.
|
||||||
|
|
||||||
|
Defines basic checks which need to be done before a user can get access to any view inheriting from
|
||||||
|
this class.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
request = check_user_is_in_any_group(request)
|
||||||
|
|
||||||
|
if not self._user_has_permission(request.user, **kwargs):
|
||||||
|
messages.info(request, MISSING_GROUP_PERMISSION)
|
||||||
|
return redirect(reverse(self._REDIRECT_URL_ERROR))
|
||||||
|
|
||||||
|
if not self._user_has_shared_access(request.user, **kwargs):
|
||||||
|
messages.info(request, DATA_UNSHARED)
|
||||||
|
return redirect(reverse(self._REDIRECT_URL_ERROR))
|
||||||
|
|
||||||
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
""" Checks whether the user has permission to get this view rendered.
|
||||||
|
|
||||||
|
If no specific check is needed, this method can be overwritten with a simple True returning.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user (User): The performing user
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
has_permission (bool): Whether the user has permission to see this view
|
||||||
|
"""
|
||||||
|
raise NotImplementedError("User permission not checked!")
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
""" Checks whether the user has shared access to this object.
|
||||||
|
|
||||||
|
If no shared-access-check is needed, this method can be overwritten with a simple True returning.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user (User): The performing user
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
has_shared_access (bool): Whether the user has shared access
|
||||||
|
"""
|
||||||
|
raise NotImplementedError("Shared access not checked!")
|
||||||
|
|
||||||
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
""" Getter to construct a more specific, data dependant redirect URL
|
||||||
|
|
||||||
|
By default the method simply returns the pre-defined redirect URL.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
url (str): Reversed redirect url
|
||||||
|
"""
|
||||||
|
return self._REDIRECT_URL
|
||||||
|
|
||||||
|
def _get_redirect_url_error(self, *args, **kwargs):
|
||||||
|
""" Getter to construct a more specific, data dependant redirect URL in error cases
|
||||||
|
|
||||||
|
By default the method simply returns the pre-defined redirect URL for errors.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
url (str): Reversed redirect url
|
||||||
|
"""
|
||||||
|
return self._REDIRECT_URL_ERROR
|
||||||
|
|
||||||
|
class BaseModalFormView(BaseView):
|
||||||
|
""" Abstract base view providing logic to perform most modal form based view renderings
|
||||||
|
|
||||||
|
"""
|
||||||
|
_TEMPLATE: str = "modal/modal_form.html"
|
||||||
|
_MODEL_CLS = None
|
||||||
|
_FORM_CLS = None
|
||||||
|
_MSG_SUCCESS = None
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
""" Checks whether the user has shared access to this object.
|
||||||
|
|
||||||
|
For objects inheriting from BaseObject class the method 'is_shared_with()' is a handy
|
||||||
|
wrapper for checking shared access. For any other circumstances this method should be overwritten
|
||||||
|
to provide custom shared-access-checking logic.
|
||||||
|
|
||||||
|
If no shared-access-check is needed, this method can be overwritten with a simple True returning.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user (User): The performing user
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
has_shared_access (bool): Whether the user has shared access
|
||||||
|
"""
|
||||||
|
obj = get_object_or_404(self._MODEL_CLS, id=kwargs.get("id"))
|
||||||
|
return obj.is_shared_with(user)
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest, *args, **kwargs):
|
||||||
|
""" GET endpoint for rendering a view holding a modal form
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# If there is an id provided as mapped parameter from the URL take it ...
|
||||||
|
_id = kwargs.pop("id", None)
|
||||||
|
try:
|
||||||
|
# ... and try to resolve it into a record
|
||||||
|
obj = self._MODEL_CLS.objects.get(id=_id)
|
||||||
|
self._check_for_recorded_instance(obj)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
# ... If there is none, maybe we are currently processing
|
||||||
|
# the creation of a new object (therefore no id yet), so let's continue
|
||||||
|
obj = None
|
||||||
|
form = self._FORM_CLS(
|
||||||
|
request.POST or None,
|
||||||
|
request.FILES or None,
|
||||||
|
instance=obj,
|
||||||
|
request=request,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
context = {
|
||||||
|
"form": form,
|
||||||
|
}
|
||||||
|
context = BaseContext(request, context).context
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
def post(self, request: HttpRequest, *args, **kwargs):
|
||||||
|
""" POST endpoint for processing form contents of a view
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# If there is an id provided as mapped parameter from the URL take it ...
|
||||||
|
_id = kwargs.pop("id", None)
|
||||||
|
try:
|
||||||
|
# ... and try to resolve it into a record
|
||||||
|
obj = self._MODEL_CLS.objects.get(id=_id)
|
||||||
|
self._check_for_recorded_instance(obj)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
# ... If there is none, maybe we are currently processing
|
||||||
|
# the creation of a new object (therefore no id yet), so let's continue
|
||||||
|
obj = None
|
||||||
|
form = self._FORM_CLS(
|
||||||
|
request.POST or None,
|
||||||
|
request.FILES or None,
|
||||||
|
instance=obj,
|
||||||
|
request=request,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
# Get now the redirect url and take specifics of the obj into account for that.
|
||||||
|
# We do not do this after saving the form to avoid side effects due to possibly changed data
|
||||||
|
redirect_url = self._get_redirect_url(obj=obj)
|
||||||
|
if form.is_valid():
|
||||||
|
# Modal forms send one POST for checking on data validity. This is used to evaluate possible errors
|
||||||
|
# on the form. The second POST (if no errors have been found) is the 'proper' one,
|
||||||
|
# which we want to process by saving/commiting of the data to the database.
|
||||||
|
if not is_ajax(request.META):
|
||||||
|
# Get now the success message and take specifics of the obj into account for that
|
||||||
|
msg_success = self._get_msg_success(obj=obj, *args, **kwargs)
|
||||||
|
form.save()
|
||||||
|
messages.success(
|
||||||
|
request,
|
||||||
|
msg_success
|
||||||
|
)
|
||||||
|
return HttpResponseRedirect(redirect_url)
|
||||||
|
else:
|
||||||
|
context = {
|
||||||
|
"form": form,
|
||||||
|
}
|
||||||
|
context = BaseContext(request, context).context
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
""" Getter to construct a more specific, data dependant redirect URL (if needed)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
url (str): Reversed redirect url
|
||||||
|
"""
|
||||||
|
obj = kwargs.get("obj", None)
|
||||||
|
if obj:
|
||||||
|
return reverse(self._REDIRECT_URL, args=(obj.id,))
|
||||||
|
else:
|
||||||
|
return reverse(self._REDIRECT_URL)
|
||||||
|
|
||||||
|
def _get_msg_success(self, *args, **kwargs):
|
||||||
|
""" Getter to construct a more specific, data dependant success message
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
return self._MSG_SUCCESS
|
||||||
|
|
||||||
|
def _check_for_recorded_instance(self, obj):
|
||||||
|
""" Checks if the object on this view is recorded and runs some special logic if so
|
||||||
|
|
||||||
|
If the instance is recorded, the view should provide some information about why the user can not edit anything.
|
||||||
|
This behaviour is only intended to mask any form for instances based on the BaseObject class.
|
||||||
|
|
||||||
|
There are situations where the form should be rendered regularly, despite the instance being recorded,
|
||||||
|
e.g. for rendering deduction form contents on (recorded) eco accounts.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
is_none = obj is None
|
||||||
|
is_other_data_type = not isinstance(obj, BaseObject)
|
||||||
|
|
||||||
|
if is_none or is_other_data_type:
|
||||||
|
# Do nothing
|
||||||
|
return
|
||||||
|
|
||||||
|
if obj.is_recorded:
|
||||||
|
# Replace default template with a blocking one
|
||||||
|
self._TEMPLATE = "form/recorded_no_edit.html"
|
||||||
|
|
||||||
|
|
||||||
|
class BaseIndexView(BaseView):
|
||||||
|
""" Abstract base class for index views
|
||||||
|
|
||||||
|
"""
|
||||||
|
_TEMPLATE: str = "generic_index.html"
|
||||||
|
_INDEX_TABLE_CLS = None
|
||||||
|
_REDIRECT_URL: str = "home"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest, *args, **kwargs):
|
||||||
|
""" GET endpoint for rendering index views
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
qs = self._get_queryset()
|
||||||
|
table = self._INDEX_TABLE_CLS(
|
||||||
|
request=request,
|
||||||
|
queryset=qs
|
||||||
|
)
|
||||||
|
context = {
|
||||||
|
"table": table,
|
||||||
|
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
||||||
|
}
|
||||||
|
context = BaseContext(request, context).context
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _get_queryset(self):
|
||||||
|
""" Generic getter for the queryset of objects which shall be processed on this view
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# No specific permissions needed for opening base index view
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
# No specific constraints for shared access of index views
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class BaseIdentifierGeneratorView(BaseView):
|
||||||
|
_MODEL_CLS = None
|
||||||
|
_REDIRECT_URL: str = "home"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest):
|
||||||
|
tmp_obj = self._MODEL_CLS()
|
||||||
|
identifier = tmp_obj.generate_new_identifier()
|
||||||
|
while self._MODEL_CLS.objects.filter(identifier=identifier).exists():
|
||||||
|
identifier = tmp_obj.generate_new_identifier()
|
||||||
|
return JsonResponse(
|
||||||
|
data={
|
||||||
|
"gen_data": identifier
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
""" Should be overwritten in inheriting classes!
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
# No specific constraints for shared access
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class BaseFormView(BaseView):
|
||||||
|
""" Abstract base class for rendering form views
|
||||||
|
|
||||||
|
"""
|
||||||
|
_MODEL_CLS = None
|
||||||
|
_FORM_CLS = None
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def _get_additional_context(self, **kwargs):
|
||||||
|
""" Getter for additional data, which is needed to properly render the current view
|
||||||
|
|
||||||
|
Args:
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
context (dict): Additional context data for rendering
|
||||||
|
"""
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSpatialLocatedObjectFormView(LoginRequiredMixin, BaseFormView):
|
||||||
|
""" Abstract base view for processing objects with spatial data
|
||||||
|
|
||||||
|
"""
|
||||||
|
_GEOMETRY_FORM_CLS = SimpleGeomForm
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
|
class BaseNewSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
||||||
|
""" Base view for creating new spatial data related to objects
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# User has to have default privilege to call this endpoint
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
# There is no shared access control since nothing exists yet
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest, *args, **kwargs):
|
||||||
|
""" GET endpoint for rendering a form view where object data and spatial data are processed
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# First initialize the regular object form and the geometry form based on request-bound data
|
||||||
|
form: BaseForm = self._FORM_CLS(None, **kwargs, user=request.user)
|
||||||
|
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(None, user=request.user, read_only=False)
|
||||||
|
|
||||||
|
# Get some additional context and put everything into the rendering pipeline
|
||||||
|
context = self._get_additional_context()
|
||||||
|
context = BaseContext(request, additional_context=context).context
|
||||||
|
context.update(
|
||||||
|
{
|
||||||
|
"form": form,
|
||||||
|
"geom_form": geom_form,
|
||||||
|
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
def post(self, request: HttpRequest, *args, **kwargs):
|
||||||
|
""" POST endpoint for processing object and spatial data provided by forms
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# First initialize the regular object form and the geometry form based on request-bound data
|
||||||
|
form: BaseForm = self._FORM_CLS(request.POST or None, **kwargs, user=request.user)
|
||||||
|
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(request.POST or None, user=request.user, read_only=False)
|
||||||
|
|
||||||
|
# Only continue if both forms are without errors
|
||||||
|
if form.is_valid() and geom_form.is_valid():
|
||||||
|
obj = form.save(request.user, geom_form)
|
||||||
|
obj_redirect_url = reverse(self._REDIRECT_URL, args=(obj.id,))
|
||||||
|
|
||||||
|
generated_identifier = form.cleaned_data.get("identifier", None)
|
||||||
|
|
||||||
|
# There is a rare chance that an identifier has been taken already between sending the form and processing
|
||||||
|
# the data. If the identifier can not be used anymore, we have to inform the user that another identifier
|
||||||
|
# had to be generated
|
||||||
|
if generated_identifier != obj.identifier:
|
||||||
|
messages.info(
|
||||||
|
request,
|
||||||
|
IDENTIFIER_REPLACED.format(
|
||||||
|
generated_identifier,
|
||||||
|
obj.identifier
|
||||||
|
)
|
||||||
|
)
|
||||||
|
messages.success(request, _("{} added").format(obj.identifier))
|
||||||
|
# Very complex geometries have to be simplified automatically while processing the spatial data. If this
|
||||||
|
# is the case, the user has to be informed. (They might want to check whether the stored geometry still
|
||||||
|
# fits their needs)
|
||||||
|
if geom_form.has_geometry_simplified():
|
||||||
|
messages.info(
|
||||||
|
request,
|
||||||
|
GEOMETRY_SIMPLIFIED
|
||||||
|
)
|
||||||
|
|
||||||
|
# If certain parts of the geometry do not pass the quality check (e.g. way too small and therefore more like
|
||||||
|
# cutting errors) we need to inform the user that some parts have been removed/ignored while storing the
|
||||||
|
# geometry
|
||||||
|
num_ignored_geometries = geom_form.get_num_geometries_ignored()
|
||||||
|
if num_ignored_geometries > 0:
|
||||||
|
messages.info(
|
||||||
|
request,
|
||||||
|
GEOMETRIES_IGNORED_TEMPLATE.format(num_ignored_geometries)
|
||||||
|
)
|
||||||
|
|
||||||
|
return redirect(obj_redirect_url)
|
||||||
|
else:
|
||||||
|
# Something was not properly entered on the forms, so we have to inform the user
|
||||||
|
context = self._get_additional_context()
|
||||||
|
messages.error(request, FORM_INVALID, extra_tags="danger",)
|
||||||
|
|
||||||
|
context = BaseContext(request, additional_context=context).context
|
||||||
|
context.update(
|
||||||
|
{
|
||||||
|
"form": form,
|
||||||
|
"geom_form": geom_form,
|
||||||
|
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseEditSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
||||||
|
""" Base view for editing new spatial data related to objects
|
||||||
|
|
||||||
|
"""
|
||||||
|
_TAB_TITLE = _("Edit {}")
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest, id: str, *args, **kwargs):
|
||||||
|
""" GET endpoint for rendering a form view where object data and spatial data are processed
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
id (str): The id of the object (not the geometry)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# First fetch the object identified by the id
|
||||||
|
obj = get_object_or_404(
|
||||||
|
self._MODEL_CLS,
|
||||||
|
id=id
|
||||||
|
)
|
||||||
|
obj_redirect_url = reverse(self._REDIRECT_URL, args=(obj.id,))
|
||||||
|
|
||||||
|
# Check whether the object is recorded. If so - we can redirect the user and inform about the un-editability
|
||||||
|
# of this entry
|
||||||
|
if obj.is_recorded:
|
||||||
|
messages.info(
|
||||||
|
request,
|
||||||
|
RECORDED_BLOCKS_EDIT
|
||||||
|
)
|
||||||
|
return redirect(obj_redirect_url)
|
||||||
|
|
||||||
|
# Seems like the object is not recorded. Good - initialize the forms based on the obj and request-bound data
|
||||||
|
form: BaseForm = self._FORM_CLS(None, instance=obj, user=request.user)
|
||||||
|
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(None, instance=obj, read_only=False)
|
||||||
|
|
||||||
|
# Get additional context for rendering and put everything in the rendering pipeline
|
||||||
|
context = self._get_additional_context()
|
||||||
|
context = BaseContext(request, additional_context=context).context
|
||||||
|
context.update(
|
||||||
|
{
|
||||||
|
"form": form,
|
||||||
|
"geom_form": geom_form,
|
||||||
|
TAB_TITLE_IDENTIFIER: self._TAB_TITLE.format(obj.identifier),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
def post(self, request: HttpRequest, id: str, *args, **kwargs):
|
||||||
|
""" POST endpoint for processing object and spatial data provided by forms
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
id (str): The object's id
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
obj = get_object_or_404(
|
||||||
|
self._MODEL_CLS,
|
||||||
|
id=id
|
||||||
|
)
|
||||||
|
obj_redirect_url = reverse(self._REDIRECT_URL, args=(obj.id,))
|
||||||
|
|
||||||
|
# If the object is recorded, we abort the processing directly and inform the user
|
||||||
|
if obj.is_recorded:
|
||||||
|
messages.info(
|
||||||
|
request,
|
||||||
|
RECORDED_BLOCKS_EDIT
|
||||||
|
)
|
||||||
|
return redirect(obj_redirect_url)
|
||||||
|
|
||||||
|
# Initialize forms with obj and request-bound data
|
||||||
|
form: BaseForm = self._FORM_CLS(request.POST or None, instance=obj, user=request.user)
|
||||||
|
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(request.POST or None, instance=obj, read_only=False)
|
||||||
|
|
||||||
|
if form.is_valid() and geom_form.is_valid():
|
||||||
|
obj = form.save(request.user, geom_form)
|
||||||
|
messages.success(request, _("{} edited").format(obj.identifier))
|
||||||
|
|
||||||
|
# Very complex geometries have to be simplified automatically while processing the spatial data. If this
|
||||||
|
# is the case, the user has to be informed. (They might want to check whether the stored geometry still
|
||||||
|
# fits their needs)
|
||||||
|
if geom_form.has_geometry_simplified():
|
||||||
|
messages.info(
|
||||||
|
request,
|
||||||
|
GEOMETRY_SIMPLIFIED
|
||||||
|
)
|
||||||
|
|
||||||
|
# If certain parts of the geometry do not pass the quality check (e.g. way too small and therefore more like
|
||||||
|
# cutting errors) we need to inform the user that some parts have been removed/ignored while storing the
|
||||||
|
# geometry
|
||||||
|
num_ignored_geometries = geom_form.get_num_geometries_ignored()
|
||||||
|
if num_ignored_geometries > 0:
|
||||||
|
messages.info(
|
||||||
|
request,
|
||||||
|
GEOMETRIES_IGNORED_TEMPLATE.format(num_ignored_geometries)
|
||||||
|
)
|
||||||
|
|
||||||
|
return redirect(obj_redirect_url)
|
||||||
|
else:
|
||||||
|
context = self._get_additional_context()
|
||||||
|
messages.error(request, FORM_INVALID, extra_tags="danger",)
|
||||||
|
|
||||||
|
context = BaseContext(request, additional_context=context).context
|
||||||
|
context.update(
|
||||||
|
{
|
||||||
|
"form": form,
|
||||||
|
"geom_form": geom_form,
|
||||||
|
TAB_TITLE_IDENTIFIER: self._TAB_TITLE.format(obj.identifier),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
obj = get_object_or_404(self._MODEL_CLS, id=kwargs.get('id', None))
|
||||||
|
return obj.is_shared_with(user)
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_default_user()
|
||||||
@ -5,102 +5,57 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 22.08.22
|
Created on: 22.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.shortcuts import get_object_or_404
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.urls import reverse
|
|
||||||
from django.views import View
|
|
||||||
|
|
||||||
from compensation.forms.modals.deadline import NewDeadlineModalForm, EditDeadlineModalForm
|
from compensation.forms.modals.deadline import NewDeadlineModalForm, EditDeadlineModalForm
|
||||||
from konova.forms.modals import RemoveDeadlineModalForm
|
from konova.forms.modals import RemoveDeadlineModalForm
|
||||||
from konova.models import Deadline
|
|
||||||
from konova.utils.message_templates import DEADLINE_ADDED, DEADLINE_EDITED, DEADLINE_REMOVED
|
from konova.utils.message_templates import DEADLINE_ADDED, DEADLINE_EDITED, DEADLINE_REMOVED
|
||||||
|
from konova.views.base import BaseModalFormView
|
||||||
|
|
||||||
|
|
||||||
class AbstractNewDeadlineView(View):
|
class AbstractNewDeadlineView(LoginRequiredMixin, BaseModalFormView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
redirect_url = None
|
_FORM_CLS = NewDeadlineModalForm
|
||||||
|
_REDIRECT_URL = None
|
||||||
|
_MSG_SUCCESS = DEADLINE_ADDED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
""" Renders a form for adding new deadlines
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
|
|
||||||
Args:
|
def _user_has_permission(self, user, **kwargs):
|
||||||
request (HttpRequest): The incoming request
|
return user.is_default_user()
|
||||||
id (str): The account's id to which the new state will be related
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
form = NewDeadlineModalForm(request.POST or None, instance=obj, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=DEADLINE_ADDED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str):
|
|
||||||
return self.get(request, id)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractEditDeadlineView(View):
|
class AbstractEditDeadlineView(LoginRequiredMixin, BaseModalFormView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
redirect_url = None
|
_FORM_CLS = EditDeadlineModalForm
|
||||||
|
_REDIRECT_URL = None
|
||||||
|
_MSG_SUCCESS = DEADLINE_EDITED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str, deadline_id: str):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
""" Renders a form for editing deadlines
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
|
|
||||||
Args:
|
def _user_has_permission(self, user, **kwargs):
|
||||||
request (HttpRequest): The incoming request
|
return user.is_default_user()
|
||||||
id (str): The compensation's id
|
|
||||||
deadline_id (str): The deadline's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
deadline = get_object_or_404(Deadline, id=deadline_id)
|
|
||||||
form = EditDeadlineModalForm(request.POST or None, instance=obj, deadline=deadline, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=DEADLINE_EDITED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str, deadline_id: str):
|
|
||||||
return self.get(request, id, deadline_id)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractRemoveDeadlineView(View):
|
class AbstractRemoveDeadlineView(LoginRequiredMixin, BaseModalFormView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
redirect_url = None
|
_FORM_CLS = RemoveDeadlineModalForm
|
||||||
|
_REDIRECT_URL = None
|
||||||
|
_MSG_SUCCESS = DEADLINE_REMOVED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str, deadline_id: str):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
""" Renders a form for removing deadlines
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
|
|
||||||
Args:
|
def _user_has_permission(self, user, **kwargs):
|
||||||
request (HttpRequest): The incoming request
|
return user.is_default_user()
|
||||||
id (str): The compensation's id
|
|
||||||
deadline_id (str): The deadline's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
deadline = get_object_or_404(Deadline, id=deadline_id)
|
|
||||||
form = RemoveDeadlineModalForm(request.POST or None, instance=obj, deadline=deadline, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=DEADLINE_REMOVED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str, deadline_id: str):
|
|
||||||
return self.get(request, id, deadline_id)
|
|
||||||
|
|||||||
@ -6,126 +6,88 @@ Created on: 22.08.22
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.http import Http404
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.views import View
|
|
||||||
|
|
||||||
from intervention.forms.modals.deduction import NewEcoAccountDeductionModalForm, EditEcoAccountDeductionModalForm, \
|
from intervention.forms.modals.deduction import NewEcoAccountDeductionModalForm, EditEcoAccountDeductionModalForm, \
|
||||||
RemoveEcoAccountDeductionModalForm
|
RemoveEcoAccountDeductionModalForm
|
||||||
from konova.utils.message_templates import DEDUCTION_ADDED, DEDUCTION_EDITED, DEDUCTION_REMOVED, DEDUCTION_UNKNOWN
|
from konova.utils.general import check_id_is_valid_uuid
|
||||||
|
from konova.views.base import BaseModalFormView
|
||||||
|
|
||||||
|
|
||||||
class AbstractDeductionView(View):
|
class AbstractDeductionView(BaseModalFormView):
|
||||||
model = None
|
_REDIRECT_URL = None
|
||||||
redirect_url = None
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
check_id_is_valid_uuid(kwargs.get("id"))
|
||||||
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def _custom_check(self, obj):
|
def _custom_check(self, obj):
|
||||||
"""
|
"""
|
||||||
Can be used by inheriting classes to provide custom checks before further processing
|
Can be used by inheriting classes to provide custom checks before further processing
|
||||||
|
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError("Must be implemented in subclasses")
|
pass
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs) -> bool:
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs) -> bool:
|
||||||
|
""" A user has shared access on
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user (User): The performing user
|
||||||
|
kwargs (dict): Parameters
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the user has access to the requested object, False otherwise
|
||||||
|
"""
|
||||||
|
ret_val: bool = False
|
||||||
|
try:
|
||||||
|
obj = self._MODEL_CLS.objects.get(
|
||||||
|
id=kwargs.get("id")
|
||||||
|
)
|
||||||
|
ret_val = obj.is_shared_with(user)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
ret_val = False
|
||||||
|
return ret_val
|
||||||
|
|
||||||
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
obj = kwargs.get("obj", None)
|
||||||
|
assert obj is not None
|
||||||
|
return reverse(self._REDIRECT_URL, args=(obj.id,)) + "#related_data"
|
||||||
|
|
||||||
|
|
||||||
class AbstractNewDeductionView(AbstractDeductionView):
|
class AbstractNewDeductionView(AbstractDeductionView):
|
||||||
|
_FORM_CLS = NewEcoAccountDeductionModalForm
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str):
|
|
||||||
""" Renders a modal form view for creating deductions
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The obj's id which shall benefit from this deduction
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
self._custom_check(obj)
|
|
||||||
form = NewEcoAccountDeductionModalForm(request.POST or None, instance=obj, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=DEDUCTION_ADDED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data",
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str):
|
|
||||||
return self.get(request, id)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractEditDeductionView(AbstractDeductionView):
|
class AbstractEditDeductionView(AbstractDeductionView):
|
||||||
|
_FORM_CLS = EditEcoAccountDeductionModalForm
|
||||||
|
|
||||||
def _custom_check(self, obj):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
pass
|
check_id_is_valid_uuid(kwargs.get("deduction_id"))
|
||||||
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str, deduction_id: str):
|
|
||||||
""" Renders a modal view for editing deductions
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The object's id
|
|
||||||
deduction_id (str): The deduction's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
self._custom_check(obj)
|
|
||||||
try:
|
|
||||||
eco_deduction = obj.deductions.get(id=deduction_id)
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
raise Http404(DEDUCTION_UNKNOWN)
|
|
||||||
|
|
||||||
form = EditEcoAccountDeductionModalForm(request.POST or None, instance=obj, deduction=eco_deduction,
|
|
||||||
request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request=request,
|
|
||||||
msg_success=DEDUCTION_EDITED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str, deduction_id: str):
|
|
||||||
return self.get(request, id, deduction_id)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractRemoveDeductionView(AbstractDeductionView):
|
class AbstractRemoveDeductionView(AbstractDeductionView):
|
||||||
|
_FORM_CLS = RemoveEcoAccountDeductionModalForm
|
||||||
|
|
||||||
def _custom_check(self, obj):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
pass
|
check_id_is_valid_uuid(kwargs.get("deduction_id"))
|
||||||
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str, deduction_id: str):
|
|
||||||
""" Renders a modal view for removing deductions
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The object's id
|
|
||||||
deduction_id (str): The deduction's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
self._custom_check(obj)
|
|
||||||
try:
|
|
||||||
eco_deduction = obj.deductions.get(id=deduction_id)
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
raise Http404(DEDUCTION_UNKNOWN)
|
|
||||||
form = RemoveEcoAccountDeductionModalForm(request.POST or None, instance=obj, deduction=eco_deduction,
|
|
||||||
request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request=request,
|
|
||||||
msg_success=DEDUCTION_REMOVED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str, deduction_id: str):
|
|
||||||
return self.get(request, id, deduction_id)
|
|
||||||
|
|||||||
107
konova/views/detail.py
Normal file
107
konova/views/detail.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
"""
|
||||||
|
Author: Michel Peltriaux
|
||||||
|
Created on: 17.10.25
|
||||||
|
|
||||||
|
"""
|
||||||
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.http import HttpRequest
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from konova.contexts import BaseContext
|
||||||
|
from konova.forms import SimpleGeomForm
|
||||||
|
from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP
|
||||||
|
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
||||||
|
from konova.utils.general import check_id_is_valid_uuid
|
||||||
|
from konova.utils.message_templates import DO_NOT_FORGET_TO_SHARE
|
||||||
|
from konova.views.base import BaseView
|
||||||
|
|
||||||
|
|
||||||
|
class BaseDetailView(LoginRequiredMixin, BaseView):
|
||||||
|
_MODEL_CLS = None
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
check_id_is_valid_uuid(kwargs.get('id'))
|
||||||
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
""" Check if user has shared access to this object
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Access to an entry's detail view is not restricted by the state of being-shared or not
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# Detail views have no restrictions
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest, id: str):
|
||||||
|
""" Get endpoint for detail view
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
id (str): The record's id
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
obj = self._get_object(id)
|
||||||
|
geom_form = SimpleGeomForm(instance=obj)
|
||||||
|
user = request.user
|
||||||
|
|
||||||
|
requesting_user_is_only_shared_user = obj.is_only_shared_with(user)
|
||||||
|
if requesting_user_is_only_shared_user:
|
||||||
|
messages.info(request, DO_NOT_FORGET_TO_SHARE)
|
||||||
|
|
||||||
|
obj.set_status_messages(request)
|
||||||
|
|
||||||
|
detail_context = self._get_detail_context(obj)
|
||||||
|
context = BaseContext(request, detail_context).context
|
||||||
|
context.update(
|
||||||
|
{
|
||||||
|
"obj": obj,
|
||||||
|
"geom_form": geom_form,
|
||||||
|
"is_default_member": user.in_group(DEFAULT_GROUP),
|
||||||
|
"is_zb_member": user.in_group(ZB_GROUP),
|
||||||
|
"is_ets_member": user.in_group(ETS_GROUP),
|
||||||
|
"LANIS_LINK": obj.get_LANIS_link(),
|
||||||
|
"is_entry_shared": obj.is_shared_with(user=user),
|
||||||
|
TAB_TITLE_IDENTIFIER: f"{obj.identifier} - {obj.title}"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return render(request,self._TEMPLATE, context)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _get_detail_context(self, obj):
|
||||||
|
""" Generate object specific detail context for view
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (): The record
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _get_object(self, id: str):
|
||||||
|
""" Fetch object for detail view
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id (str): The record's id'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
@ -5,46 +5,35 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 22.08.22
|
Created on: 22.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.http import HttpRequest
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.urls import reverse
|
|
||||||
from django.views import View
|
|
||||||
|
|
||||||
from konova.utils.documents import get_document, remove_document
|
from konova.forms.modals import EditDocumentModalForm
|
||||||
from konova.utils.message_templates import DOCUMENT_ADDED, DOCUMENT_EDITED
|
from konova.utils.documents import get_document
|
||||||
|
from konova.utils.message_templates import DOCUMENT_ADDED, DOCUMENT_EDITED, DOCUMENT_REMOVED_TEMPLATE
|
||||||
|
from konova.views.base import BaseModalFormView, BaseView
|
||||||
|
|
||||||
|
|
||||||
class AbstractNewDocumentView(View):
|
class AbstractNewDocumentView(LoginRequiredMixin, BaseModalFormView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
form = None
|
_FORM_CLS = None
|
||||||
redirect_url = None
|
_REDIRECT_URL = None
|
||||||
|
_MSG_SUCCESS = DOCUMENT_ADDED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
""" Renders a form for uploading new documents
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
|
|
||||||
Args:
|
def _user_has_permission(self, user, **kwargs):
|
||||||
request (HttpRequest): The incoming request
|
return user.is_default_user()
|
||||||
id (str): The object's id to which the new document will be related
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
intervention = get_object_or_404(self.model, id=id)
|
|
||||||
form = self.form(request.POST or None, request.FILES or None, instance=intervention, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=DOCUMENT_ADDED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str):
|
|
||||||
return self.get(request, id)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractGetDocumentView(View):
|
class AbstractGetDocumentView(LoginRequiredMixin, BaseView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
document_model = None
|
_DOCUMENT_CLS = None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
@ -62,77 +51,57 @@ class AbstractGetDocumentView(View):
|
|||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
get_object_or_404(self.model, id=id)
|
get_object_or_404(self._MODEL_CLS, id=id)
|
||||||
doc = get_object_or_404(self.document_model, id=doc_id)
|
doc = get_object_or_404(self._DOCUMENT_CLS, id=doc_id)
|
||||||
return get_document(doc)
|
return get_document(doc)
|
||||||
|
|
||||||
def post(self, request, id: str, doc_id: str):
|
def post(self, request, id: str, doc_id: str):
|
||||||
return self.get(request, id, doc_id)
|
return self.get(request, id, doc_id)
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
class AbstractRemoveDocumentView(View):
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
model = None
|
obj = kwargs.get("id", None)
|
||||||
document_model = None
|
assert obj is not None
|
||||||
|
obj = get_object_or_404(self._MODEL_CLS, id=obj)
|
||||||
|
return obj.is_shared_with(user)
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractRemoveDocumentView(LoginRequiredMixin, BaseModalFormView):
|
||||||
|
_MODEL_CLS = None
|
||||||
|
_DOCUMENT_CLS = None
|
||||||
|
_FORM_CLS = None
|
||||||
|
_MSG_SUCCESS = DOCUMENT_REMOVED_TEMPLATE
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str, doc_id: str):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
""" Removes the document from the database and file system
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
|
|
||||||
Wraps the generic functionality from konova.utils.
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
Args:
|
def _get_msg_success(self, *args, **kwargs):
|
||||||
request (HttpRequest): The incoming request
|
doc_id = kwargs.get("doc_id", None)
|
||||||
id (str): The intervention id
|
assert doc_id is not None
|
||||||
doc_id (str): The document id
|
doc = get_object_or_404(self._DOCUMENT_CLS, id=doc_id)
|
||||||
|
return self._MSG_SUCCESS.format(doc.title)
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
get_object_or_404(self.model, id=id)
|
|
||||||
doc = get_object_or_404(self.document_model, id=doc_id)
|
|
||||||
return remove_document(
|
|
||||||
request,
|
|
||||||
doc
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str, doc_id: str):
|
|
||||||
return self.get(request, id, doc_id)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractEditDocumentView(View):
|
class AbstractEditDocumentView(LoginRequiredMixin, BaseModalFormView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
document_model = None
|
_DOCUMENT_CLS = None
|
||||||
form = None
|
_FORM_CLS = EditDocumentModalForm
|
||||||
redirect_url = None
|
_REDIRECT_URL = None
|
||||||
|
_MSG_SUCCESS = DOCUMENT_EDITED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str, doc_id: str):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
""" GET handling for editing of existing document
|
return user.is_default_user()
|
||||||
|
|
||||||
Wraps the generic functionality from konova.utils.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The intervention id
|
|
||||||
doc_id (str): The document id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
doc = get_object_or_404(self.document_model, id=doc_id)
|
|
||||||
form = self.form(request.POST or None, request.FILES or None, instance=obj, document=doc,
|
|
||||||
request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
DOCUMENT_EDITED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(obj.id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str, doc_id: str):
|
|
||||||
return self.get(request, id, doc_id)
|
|
||||||
|
|
||||||
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
@ -10,15 +10,16 @@ from django.http import HttpResponse, HttpRequest
|
|||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.views import View
|
|
||||||
|
|
||||||
from konova.models import Geometry
|
from konova.models import Geometry
|
||||||
from konova.settings import GEOM_THRESHOLD_RECALCULATION_SECONDS
|
from konova.settings import GEOM_THRESHOLD_RECALCULATION_SECONDS
|
||||||
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
|
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
|
||||||
from konova.tasks import celery_update_parcels
|
from konova.tasks import celery_update_parcels
|
||||||
|
from konova.views.base import BaseView
|
||||||
|
|
||||||
|
|
||||||
class GeomParcelsView(View):
|
class GeomParcelsView(BaseView):
|
||||||
|
_TEMPLATE = "konova/includes/parcels/parcel_table_frame.html"
|
||||||
|
|
||||||
def get(self, request: HttpRequest, id: str):
|
def get(self, request: HttpRequest, id: str):
|
||||||
""" Getter for HTMX
|
""" Getter for HTMX
|
||||||
@ -32,7 +33,6 @@ class GeomParcelsView(View):
|
|||||||
Returns:
|
Returns:
|
||||||
A rendered piece of HTML
|
A rendered piece of HTML
|
||||||
"""
|
"""
|
||||||
template = "konova/includes/parcels/parcel_table_frame.html"
|
|
||||||
|
|
||||||
geom = get_object_or_404(Geometry, id=id)
|
geom = get_object_or_404(Geometry, id=id)
|
||||||
geos_geom = geom.geom or MultiPolygon(srid=DEFAULT_SRID_RLP)
|
geos_geom = geom.geom or MultiPolygon(srid=DEFAULT_SRID_RLP)
|
||||||
@ -85,7 +85,7 @@ class GeomParcelsView(View):
|
|||||||
"geom_id": str(id),
|
"geom_id": str(id),
|
||||||
"next_page": next_page,
|
"next_page": next_page,
|
||||||
}
|
}
|
||||||
html = render_to_string(template, context, request)
|
html = render_to_string(self._TEMPLATE, context, request)
|
||||||
return HttpResponse(html, status=status_code)
|
return HttpResponse(html, status=status_code)
|
||||||
else:
|
else:
|
||||||
return HttpResponse(None, status=404)
|
return HttpResponse(None, status=404)
|
||||||
@ -107,8 +107,15 @@ class GeomParcelsView(View):
|
|||||||
waiting_too_long = (pcs_diff >= wait_for_seconds)
|
waiting_too_long = (pcs_diff >= wait_for_seconds)
|
||||||
return waiting_too_long
|
return waiting_too_long
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
return True
|
||||||
|
|
||||||
class GeomParcelsContentView(View):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class GeomParcelsContentView(BaseView):
|
||||||
|
_TEMPLATE = "konova/includes/parcels/parcel_table_content.html"
|
||||||
|
|
||||||
def get(self, request: HttpRequest, id: str, page: int):
|
def get(self, request: HttpRequest, id: str, page: int):
|
||||||
""" Getter for infinite scroll of HTMX
|
""" Getter for infinite scroll of HTMX
|
||||||
@ -130,7 +137,6 @@ class GeomParcelsContentView(View):
|
|||||||
# HTTP code 286 states that the HTMX should stop polling for updates
|
# HTTP code 286 states that the HTMX should stop polling for updates
|
||||||
# https://htmx.org/docs/#polling
|
# https://htmx.org/docs/#polling
|
||||||
status_code = 286
|
status_code = 286
|
||||||
template = "konova/includes/parcels/parcel_table_content.html"
|
|
||||||
geom = get_object_or_404(Geometry, id=id)
|
geom = get_object_or_404(Geometry, id=id)
|
||||||
parcels = geom.get_underlying_parcels()
|
parcels = geom.get_underlying_parcels()
|
||||||
|
|
||||||
@ -148,5 +154,11 @@ class GeomParcelsContentView(View):
|
|||||||
"geom_id": str(id),
|
"geom_id": str(id),
|
||||||
"next_page": next_page,
|
"next_page": next_page,
|
||||||
}
|
}
|
||||||
html = render_to_string(template, context, request)
|
html = render_to_string(self._TEMPLATE, context, request)
|
||||||
return HttpResponse(html, status=status_code)
|
return HttpResponse(html, status=status_code)
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return True
|
||||||
|
|||||||
@ -9,21 +9,19 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views import View
|
|
||||||
|
|
||||||
from compensation.models import EcoAccount, Compensation
|
from compensation.models import EcoAccount, Compensation
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.contexts import BaseContext
|
from konova.contexts import BaseContext
|
||||||
from konova.decorators import any_group_check
|
|
||||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
||||||
|
from konova.views.base import BaseView
|
||||||
from news.models import ServerMessage
|
from news.models import ServerMessage
|
||||||
|
|
||||||
|
|
||||||
class HomeView(LoginRequiredMixin, View):
|
class HomeView(LoginRequiredMixin, BaseView):
|
||||||
|
_TEMPLATE = "konova/home.html"
|
||||||
|
|
||||||
@method_decorator(any_group_check)
|
|
||||||
def get(self, request: HttpRequest):
|
def get(self, request: HttpRequest):
|
||||||
"""
|
"""
|
||||||
Renders the landing page
|
Renders the landing page
|
||||||
@ -34,7 +32,6 @@ class HomeView(LoginRequiredMixin, View):
|
|||||||
Returns:
|
Returns:
|
||||||
A redirect
|
A redirect
|
||||||
"""
|
"""
|
||||||
template = "konova/home.html"
|
|
||||||
user = request.user
|
user = request.user
|
||||||
user_teams = user.shared_teams
|
user_teams = user.shared_teams
|
||||||
|
|
||||||
@ -75,5 +72,12 @@ class HomeView(LoginRequiredMixin, View):
|
|||||||
TAB_TITLE_IDENTIFIER: _("Home"),
|
TAB_TITLE_IDENTIFIER: _("Home"),
|
||||||
}
|
}
|
||||||
context = BaseContext(request, additional_context).context
|
context = BaseContext(request, additional_context).context
|
||||||
return render(request, template, context)
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# No specific permission needed for home view
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
# No specific constraint needed for home view
|
||||||
|
return True
|
||||||
|
|||||||
@ -6,14 +6,15 @@ Created on: 19.08.22
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.views import View
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from konova.contexts import BaseContext
|
from konova.contexts import BaseContext
|
||||||
|
from konova.views.base import BaseView
|
||||||
|
|
||||||
|
|
||||||
class AbstractLogView(View):
|
class AbstractLogView(BaseView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
|
_TEMPLATE = "modal/modal_generic.html"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
@ -28,14 +29,22 @@ class AbstractLogView(View):
|
|||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
intervention = get_object_or_404(self.model, id=id)
|
intervention = get_object_or_404(self._MODEL_CLS, id=id)
|
||||||
template = "modal/modal_generic.html"
|
|
||||||
body_template = "log.html"
|
body_template = "log.html"
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
"modal_body_template": body_template,
|
"modal_body_template": body_template,
|
||||||
"log": intervention.log.all(),
|
"log": intervention.log.iterator(),
|
||||||
"modal_title": _("Log"),
|
"modal_title": _("Log"),
|
||||||
}
|
}
|
||||||
context = BaseContext(request, context).context
|
context = BaseContext(request, context).context
|
||||||
return render(request, template, context)
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
obj_id = kwargs.get('id', None)
|
||||||
|
assert obj_id is not None
|
||||||
|
obj = get_object_or_404(self._MODEL_CLS, id=obj_id)
|
||||||
|
return obj.is_shared_with(user)
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_default_user()
|
||||||
|
|||||||
@ -10,9 +10,8 @@ from json import JSONDecodeError
|
|||||||
|
|
||||||
import requests
|
import requests
|
||||||
import urllib3.util
|
import urllib3.util
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.http import JsonResponse, HttpRequest, HttpResponse
|
from django.http import JsonResponse, HttpRequest, HttpResponse
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
from django.views import View
|
from django.views import View
|
||||||
|
|
||||||
@ -22,17 +21,13 @@ from konova.sub_settings.lanis_settings import MAP_PROXY_HOST_WHITELIST
|
|||||||
from konova.sub_settings.proxy_settings import PROXIES, GEOPORTAL_RLP_USER, GEOPORTAL_RLP_PASSWORD
|
from konova.sub_settings.proxy_settings import PROXIES, GEOPORTAL_RLP_USER, GEOPORTAL_RLP_PASSWORD
|
||||||
|
|
||||||
|
|
||||||
class BaseClientProxyView(View):
|
class BaseClientProxyView(LoginRequiredMixin, View):
|
||||||
""" Provides proxy functionality for NETGIS map client.
|
""" Provides proxy functionality for NETGIS map client.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
@method_decorator(login_required)
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def _check_with_whitelist(self, url):
|
def _check_with_whitelist(self, url):
|
||||||
parsed_url = urllib3.util.parse_url(url)
|
parsed_url = urllib3.util.parse_url(url)
|
||||||
parsed_url_host = parsed_url.host
|
parsed_url_host = parsed_url.host
|
||||||
@ -67,7 +62,6 @@ class BaseClientProxyView(View):
|
|||||||
|
|
||||||
|
|
||||||
class ClientProxyParcelSearch(BaseClientProxyView):
|
class ClientProxyParcelSearch(BaseClientProxyView):
|
||||||
|
|
||||||
def get(self, request: HttpRequest):
|
def get(self, request: HttpRequest):
|
||||||
url = request.META.get("QUERY_STRING")
|
url = request.META.get("QUERY_STRING")
|
||||||
|
|
||||||
|
|||||||
@ -5,46 +5,28 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.views import View
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
from konova.forms.modals import RecordModalForm
|
from konova.forms.modals import RecordModalForm
|
||||||
|
from konova.utils.message_templates import ENTRY_RECORDED, ENTRY_UNRECORDED
|
||||||
|
from konova.views.base import BaseModalFormView
|
||||||
|
|
||||||
|
|
||||||
class AbstractRecordView(View):
|
class AbstractRecordView(BaseModalFormView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
|
_FORM_CLS = RecordModalForm
|
||||||
|
_MSG_SUCCESS = None
|
||||||
|
|
||||||
def get(self, request, id: str):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
""" Renders a modal form for recording an object
|
return user.is_ets_user()
|
||||||
|
|
||||||
Args:
|
def _get_msg_success(self, *args, **kwargs):
|
||||||
request (HttpRequest): The incoming request
|
obj = kwargs.get("obj")
|
||||||
id (str): The object's id
|
assert obj is not None
|
||||||
|
|
||||||
Returns:
|
if obj.is_recorded:
|
||||||
|
return ENTRY_RECORDED.format(obj.identifier)
|
||||||
|
else:
|
||||||
|
return ENTRY_UNRECORDED.format(obj.identifier)
|
||||||
|
|
||||||
"""
|
def _check_for_recorded_instance(self, obj):
|
||||||
obj = get_object_or_404(self.model, id=id)
|
# Do not block record view if instance might be recorded
|
||||||
form = RecordModalForm(request.POST or None, instance=obj, request=request)
|
return None
|
||||||
msg_succ = _("{} unrecorded") if obj.recorded else _("{} recorded")
|
|
||||||
msg_succ = msg_succ.format(obj.identifier)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_succ,
|
|
||||||
msg_error=_("Errors found:")
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str):
|
|
||||||
"""
|
|
||||||
|
|
||||||
BaseModalForm provides the method process_request() which handles GET as well as POST requests. It was written
|
|
||||||
for easier handling of function based views. To support process_request() on class based views, the post()
|
|
||||||
call needs to be treated the same way as the get() call.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): Intervention's id
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self.get(request, id)
|
|
||||||
28
konova/views/remove.py
Normal file
28
konova/views/remove.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""
|
||||||
|
Author: Michel Peltriaux
|
||||||
|
Created on: 21.10.25
|
||||||
|
|
||||||
|
"""
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from konova.forms.modals import RemoveModalForm
|
||||||
|
from konova.utils.message_templates import GENERIC_REMOVED_TEMPLATE
|
||||||
|
from konova.views.base import BaseModalFormView
|
||||||
|
|
||||||
|
|
||||||
|
class BaseRemoveModalFormView(BaseModalFormView):
|
||||||
|
_MODEL_CLS = None
|
||||||
|
_FORM_CLS = RemoveModalForm
|
||||||
|
_MSG_SUCCESS = GENERIC_REMOVED_TEMPLATE
|
||||||
|
_REDIRECT_URL = None
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
return reverse(self._REDIRECT_URL)
|
||||||
|
|
||||||
|
def _get_msg_success(self, *args, **kwargs):
|
||||||
|
obj = kwargs.get("obj", None)
|
||||||
|
assert obj is not None
|
||||||
|
return self._MSG_SUCCESS.format(obj.identifier)
|
||||||
106
konova/views/report.py
Normal file
106
konova/views/report.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
"""
|
||||||
|
Author: Michel Peltriaux
|
||||||
|
Created on: 17.10.25
|
||||||
|
|
||||||
|
"""
|
||||||
|
from abc import abstractmethod
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
from django.http import HttpRequest, Http404
|
||||||
|
from django.shortcuts import get_object_or_404, render
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from konova.contexts import BaseContext
|
||||||
|
from konova.forms import SimpleGeomForm
|
||||||
|
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
||||||
|
from konova.views.base import BaseView
|
||||||
|
|
||||||
|
|
||||||
|
class BaseReportView(BaseView):
|
||||||
|
_TEMPLATE = None
|
||||||
|
_TAB_TITLE = _("Report {}")
|
||||||
|
_MODEL = None
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
# If the given id is not a uuid we act as the result was not found
|
||||||
|
try:
|
||||||
|
UUID(kwargs.get('id'))
|
||||||
|
except ValueError:
|
||||||
|
raise Http404()
|
||||||
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def _return_unpublishable_content_response(self, request: HttpRequest, tab_title: str):
|
||||||
|
""" Handles HttpResponse return in case the object is not ready for publish
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request ():
|
||||||
|
tab_title ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
template = "report/unavailable.html"
|
||||||
|
context = {
|
||||||
|
TAB_TITLE_IDENTIFIER: tab_title,
|
||||||
|
}
|
||||||
|
context = BaseContext(request, context).context
|
||||||
|
return render(request, template, context)
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest, id: str):
|
||||||
|
""" Renders the public report view
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
id (str): The id of the intervention
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
obj = get_object_or_404(self._MODEL, id=id)
|
||||||
|
tab_title = self._TAB_TITLE.format(obj.identifier)
|
||||||
|
|
||||||
|
# If object is not recorded we need to render another template without any data
|
||||||
|
if not obj.is_ready_for_publish():
|
||||||
|
return self._return_unpublishable_content_response(request, tab_title)
|
||||||
|
|
||||||
|
# First get specific report context for different types of objects due to inheritance
|
||||||
|
report_context = self._get_report_context(obj)
|
||||||
|
|
||||||
|
# Then generate and add default report context (the same for all models)
|
||||||
|
geom_form = SimpleGeomForm(instance=obj)
|
||||||
|
parcels = obj.get_underlying_parcels()
|
||||||
|
report_context.update(
|
||||||
|
{
|
||||||
|
TAB_TITLE_IDENTIFIER: tab_title,
|
||||||
|
"parcels": parcels,
|
||||||
|
"geom_form": geom_form,
|
||||||
|
"obj": obj
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Then generate the general context based on the report specific data
|
||||||
|
context = BaseContext(request, report_context).context
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _get_report_context(self, obj):
|
||||||
|
""" Returns the specific context needed for this report view
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj (RecordableObjectMixin): The object for the report
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: The object specific context for rendering the report
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# Reports do not need specific permissions to be callable
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
# Reports do not need specific share states to be callable
|
||||||
|
return True
|
||||||
@ -5,51 +5,24 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 19.08.22
|
Created on: 19.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.shortcuts import get_object_or_404
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.urls import reverse
|
|
||||||
from django.views import View
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
from konova.forms.modals import ResubmissionModalForm
|
from konova.utils.message_templates import NEW_RESUBMISSION_CREATED
|
||||||
|
from konova.views.base import BaseModalFormView
|
||||||
|
|
||||||
|
|
||||||
class AbstractResubmissionView(View):
|
class AbstractResubmissionView(LoginRequiredMixin, BaseModalFormView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
form_action_url_base = None
|
_FORM_CLS = None
|
||||||
redirect_url_base = None
|
_REDIRECT_URL = None
|
||||||
|
_MSG_SUCCESS = NEW_RESUBMISSION_CREATED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
""" Renders resubmission form for an object
|
return user.is_default_user()
|
||||||
|
|
||||||
Args:
|
def _check_for_recorded_instance(self, obj):
|
||||||
request (HttpRequest): The incoming request
|
# Resubmissions are allowed despite an entry being recorded
|
||||||
id (str): Object's id
|
return None
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
form = ResubmissionModalForm(request.POST or None, instance=obj, request=request)
|
|
||||||
form.action_url = reverse(self.form_action_url_base, args=(id,))
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=_("Resubmission set"),
|
|
||||||
redirect_url=reverse(self.redirect_url_base, args=(id,))
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str):
|
|
||||||
"""
|
|
||||||
|
|
||||||
BaseModalForm provides the method process_request() which handles GET as well as POST requests. It was written
|
|
||||||
for easier handling of function based views. To support process_request() on class based views, the post()
|
|
||||||
call needs to be treated the same way as the get() call.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): Intervention's id
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self.get(request, id)
|
|
||||||
@ -6,24 +6,24 @@ Created on: 22.08.22
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.views import View
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from intervention.forms.modals.share import ShareModalForm
|
from intervention.forms.modals.share import ShareModalForm
|
||||||
from konova.utils.message_templates import DATA_SHARE_SET
|
from konova.utils.message_templates import DATA_SHARE_SET
|
||||||
|
from konova.views.base import BaseView, BaseModalFormView
|
||||||
|
|
||||||
|
|
||||||
class AbstractShareByTokenView(View):
|
class AbstractShareByTokenView(LoginRequiredMixin, BaseView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
redirect_url = None
|
_REDIRECT_URL = None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str, token: str):
|
def get(self, request, id: str, token: str):
|
||||||
|
""" Performs sharing of an entry
|
||||||
""" Performs sharing of an intervention
|
|
||||||
|
|
||||||
If token given in url is not valid, the user will be redirected to the dashboard
|
If token given in url is not valid, the user will be redirected to the dashboard
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ class AbstractShareByTokenView(View):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
user = request.user
|
user = request.user
|
||||||
obj = get_object_or_404(self.model, id=id)
|
obj = get_object_or_404(self._MODEL_CLS, id=id)
|
||||||
# Check tokens
|
# Check tokens
|
||||||
if obj.access_token == token:
|
if obj.access_token == token:
|
||||||
# Send different messages in case user has already been added to list of sharing users
|
# Send different messages in case user has already been added to list of sharing users
|
||||||
@ -51,7 +51,7 @@ class AbstractShareByTokenView(View):
|
|||||||
_("{} has been shared with you").format(obj.identifier)
|
_("{} has been shared with you").format(obj.identifier)
|
||||||
)
|
)
|
||||||
obj.share_with_user(user)
|
obj.share_with_user(user)
|
||||||
return redirect(self.redirect_url, id=id)
|
return redirect(self._REDIRECT_URL, id=id)
|
||||||
else:
|
else:
|
||||||
messages.error(
|
messages.error(
|
||||||
request,
|
request,
|
||||||
@ -60,29 +60,22 @@ class AbstractShareByTokenView(View):
|
|||||||
)
|
)
|
||||||
return redirect("home")
|
return redirect("home")
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# No permissions are needed to get shared access via token
|
||||||
|
return True
|
||||||
|
|
||||||
class AbstractShareFormView(View):
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
model = None
|
# The user does not need to have shared access to call the endpoint which gives them shared access
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractShareFormView(LoginRequiredMixin, BaseModalFormView):
|
||||||
|
_MODEL_CLS = None
|
||||||
|
_FORM_CLS = ShareModalForm
|
||||||
|
_MSG_SUCCESS = DATA_SHARE_SET
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
""" Renders sharing form
|
return user.is_default_user()
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): Object's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
form = ShareModalForm(request.POST or None, instance=obj, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=DATA_SHARE_SET
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str):
|
|
||||||
return self.get(request, id)
|
|
||||||
|
|||||||
@ -5,103 +5,53 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
|||||||
Created on: 22.08.22
|
Created on: 22.08.22
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.shortcuts import get_object_or_404
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.views import View
|
|
||||||
|
|
||||||
from compensation.forms.modals.state import NewCompensationStateModalForm, EditCompensationStateModalForm, \
|
from compensation.forms.modals.state import NewCompensationStateModalForm, EditCompensationStateModalForm, \
|
||||||
RemoveCompensationStateModalForm
|
RemoveCompensationStateModalForm
|
||||||
from compensation.models import CompensationState
|
|
||||||
from konova.utils.message_templates import COMPENSATION_STATE_ADDED, COMPENSATION_STATE_EDITED, \
|
from konova.utils.message_templates import COMPENSATION_STATE_ADDED, COMPENSATION_STATE_EDITED, \
|
||||||
COMPENSATION_STATE_REMOVED
|
COMPENSATION_STATE_REMOVED
|
||||||
|
from konova.views.base import BaseModalFormView
|
||||||
|
|
||||||
|
|
||||||
class AbstractCompensationStateView(View):
|
class AbstractCompensationStateView(LoginRequiredMixin, BaseModalFormView):
|
||||||
model = None
|
_MODEL_CLS = None
|
||||||
redirect_url = None
|
_FORM_CLS = None
|
||||||
|
_REDIRECT_URL = None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return user.is_default_user()
|
||||||
|
|
||||||
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
obj = kwargs.get("obj", None)
|
||||||
|
assert obj is not None
|
||||||
|
return reverse(self._REDIRECT_URL, args=(obj.id,)) + "#related_data"
|
||||||
|
|
||||||
class AbstractNewCompensationStateView(AbstractCompensationStateView):
|
class AbstractNewCompensationStateView(AbstractCompensationStateView):
|
||||||
|
_MODEL_CLS = None
|
||||||
|
_FORM_CLS = NewCompensationStateModalForm
|
||||||
|
_MSG_SUCCESS = COMPENSATION_STATE_ADDED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str):
|
|
||||||
""" Renders a form for adding new states
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The object's id to which the new state will be related
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
form = NewCompensationStateModalForm(request.POST or None, instance=obj, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=COMPENSATION_STATE_ADDED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str):
|
|
||||||
return self.get(request, id)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractEditCompensationStateView(AbstractCompensationStateView):
|
class AbstractEditCompensationStateView(AbstractCompensationStateView):
|
||||||
|
_MODEL_CLS = None
|
||||||
|
_FORM_CLS = EditCompensationStateModalForm
|
||||||
|
_MSG_SUCCESS = COMPENSATION_STATE_EDITED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str, state_id: str):
|
|
||||||
""" Renders a form for editing a state
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The object id
|
|
||||||
state_id (str): The state's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
state = get_object_or_404(CompensationState, id=state_id)
|
|
||||||
form = EditCompensationStateModalForm(request.POST or None, instance=obj, state=state, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=COMPENSATION_STATE_EDITED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str, state_id: str):
|
|
||||||
return self.get(request, id, state_id)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractRemoveCompensationStateView(AbstractCompensationStateView):
|
class AbstractRemoveCompensationStateView(AbstractCompensationStateView):
|
||||||
|
_MODEL_CLS = None
|
||||||
|
_FORM_CLS = RemoveCompensationStateModalForm
|
||||||
|
_MSG_SUCCESS = COMPENSATION_STATE_REMOVED
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request, id: str, state_id: str):
|
|
||||||
""" Renders a form for removing astate
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The object id
|
|
||||||
state_id (str): The state's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
obj = get_object_or_404(self.model, id=id)
|
|
||||||
state = get_object_or_404(CompensationState, id=state_id)
|
|
||||||
form = RemoveCompensationStateModalForm(request.POST or None, instance=obj, state=state, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=COMPENSATION_STATE_REMOVED,
|
|
||||||
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
def post(self, request, id: str, state_id: str):
|
|
||||||
return self.get(request, id, state_id)
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@ -45,7 +45,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-15 09:11+0200\n"
|
"POT-Creation-Date: 2025-10-19 13:56+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -448,11 +448,19 @@ msgid "Select the intervention for which this compensation compensates"
|
|||||||
msgstr "Wählen Sie den Eingriff, für den diese Kompensation bestimmt ist"
|
msgstr "Wählen Sie den Eingriff, für den diese Kompensation bestimmt ist"
|
||||||
|
|
||||||
#: compensation/forms/compensation.py:114
|
#: compensation/forms/compensation.py:114
|
||||||
#: compensation/views/compensation/compensation.py:120
|
#: compensation/views/compensation/compensation.py:161
|
||||||
msgid "New compensation"
|
msgid "New compensation"
|
||||||
msgstr "Neue Kompensation"
|
msgstr "Neue Kompensation"
|
||||||
|
|
||||||
#: compensation/forms/compensation.py:190
|
#: compensation/forms/compensation.py:179
|
||||||
|
msgid ""
|
||||||
|
"This intervention is currently recorded. You cannot add further "
|
||||||
|
"compensations as long as it is recorded."
|
||||||
|
msgstr ""
|
||||||
|
"Dieser Eingriff ist derzeit verzeichnet. "
|
||||||
|
"Sie können keine weiteren Kompensationen hinzufügen, so lange er verzeichnet ist."
|
||||||
|
|
||||||
|
#: compensation/forms/compensation.py:202
|
||||||
msgid "Edit compensation"
|
msgid "Edit compensation"
|
||||||
msgstr "Bearbeite Kompensation"
|
msgstr "Bearbeite Kompensation"
|
||||||
|
|
||||||
@ -475,7 +483,7 @@ msgid "When did the parties agree on this?"
|
|||||||
msgstr "Wann wurde dieses Ökokonto offiziell vereinbart?"
|
msgstr "Wann wurde dieses Ökokonto offiziell vereinbart?"
|
||||||
|
|
||||||
#: compensation/forms/eco_account.py:72
|
#: compensation/forms/eco_account.py:72
|
||||||
#: compensation/views/eco_account/eco_account.py:101
|
#: compensation/views/eco_account/eco_account.py:93
|
||||||
msgid "New Eco-Account"
|
msgid "New Eco-Account"
|
||||||
msgstr "Neues Ökokonto"
|
msgstr "Neues Ökokonto"
|
||||||
|
|
||||||
@ -1288,44 +1296,45 @@ msgstr ""
|
|||||||
msgid "Responsible data"
|
msgid "Responsible data"
|
||||||
msgstr "Daten zu den verantwortlichen Stellen"
|
msgstr "Daten zu den verantwortlichen Stellen"
|
||||||
|
|
||||||
#: compensation/views/compensation/compensation.py:58
|
#: compensation/views/compensation/compensation.py:35
|
||||||
msgid "Compensations - Overview"
|
msgid "Compensations - Overview"
|
||||||
msgstr "Kompensationen - Übersicht"
|
msgstr "Kompensationen - Übersicht"
|
||||||
|
|
||||||
#: compensation/views/compensation/compensation.py:181
|
#: compensation/views/compensation/compensation.py:52
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "New compensation"
|
||||||
|
msgid "New Compensation"
|
||||||
|
msgstr "Neue Kompensation"
|
||||||
|
|
||||||
|
#: compensation/views/compensation/compensation.py:208
|
||||||
#: konova/utils/message_templates.py:40
|
#: konova/utils/message_templates.py:40
|
||||||
msgid "Compensation {} edited"
|
msgid "Compensation {} edited"
|
||||||
msgstr "Kompensation {} bearbeitet"
|
msgstr "Kompensation {} bearbeitet"
|
||||||
|
|
||||||
#: compensation/views/compensation/compensation.py:196
|
#: compensation/views/compensation/compensation.py:231
|
||||||
#: compensation/views/eco_account/eco_account.py:173 ema/views/ema.py:238
|
#: compensation/views/eco_account/eco_account.py:159 ema/views/ema.py:59
|
||||||
#: intervention/views/intervention.py:253
|
#: intervention/views/intervention.py:59 intervention/views/intervention.py:179
|
||||||
|
#: konova/views/base.py:239
|
||||||
msgid "Edit {}"
|
msgid "Edit {}"
|
||||||
msgstr "Bearbeite {}"
|
msgstr "Bearbeite {}"
|
||||||
|
|
||||||
#: compensation/views/compensation/report.py:35
|
#: compensation/views/eco_account/eco_account.py:32
|
||||||
#: compensation/views/eco_account/report.py:36 ema/views/report.py:35
|
|
||||||
#: intervention/views/report.py:35
|
|
||||||
msgid "Report {}"
|
|
||||||
msgstr "Bericht {}"
|
|
||||||
|
|
||||||
#: compensation/views/eco_account/eco_account.py:53
|
|
||||||
msgid "Eco-account - Overview"
|
msgid "Eco-account - Overview"
|
||||||
msgstr "Ökokonten - Übersicht"
|
msgstr "Ökokonten - Übersicht"
|
||||||
|
|
||||||
#: compensation/views/eco_account/eco_account.py:86
|
#: compensation/views/eco_account/eco_account.py:70
|
||||||
msgid "Eco-Account {} added"
|
msgid "Eco-Account {} added"
|
||||||
msgstr "Ökokonto {} hinzugefügt"
|
msgstr "Ökokonto {} hinzugefügt"
|
||||||
|
|
||||||
#: compensation/views/eco_account/eco_account.py:158
|
#: compensation/views/eco_account/eco_account.py:136
|
||||||
msgid "Eco-Account {} edited"
|
msgid "Eco-Account {} edited"
|
||||||
msgstr "Ökokonto {} bearbeitet"
|
msgstr "Ökokonto {} bearbeitet"
|
||||||
|
|
||||||
#: compensation/views/eco_account/eco_account.py:288
|
#: compensation/views/eco_account/eco_account.py:260
|
||||||
msgid "Eco-account removed"
|
msgid "Eco-account removed"
|
||||||
msgstr "Ökokonto entfernt"
|
msgstr "Ökokonto entfernt"
|
||||||
|
|
||||||
#: ema/forms.py:42 ema/tests/unit/test_forms.py:27 ema/views/ema.py:108
|
#: ema/forms.py:42 ema/tests/unit/test_forms.py:27 ema/views/ema.py:42
|
||||||
msgid "New EMA"
|
msgid "New EMA"
|
||||||
msgstr "Neue EMA hinzufügen"
|
msgstr "Neue EMA hinzufügen"
|
||||||
|
|
||||||
@ -1353,19 +1362,11 @@ msgstr ""
|
|||||||
msgid "Payment funded compensation"
|
msgid "Payment funded compensation"
|
||||||
msgstr "Ersatzzahlungsmaßnahme"
|
msgstr "Ersatzzahlungsmaßnahme"
|
||||||
|
|
||||||
#: ema/views/ema.py:53
|
#: ema/views/ema.py:26
|
||||||
msgid "EMAs - Overview"
|
msgid "EMAs - Overview"
|
||||||
msgstr "EMAs - Übersicht"
|
msgstr "EMAs - Übersicht"
|
||||||
|
|
||||||
#: ema/views/ema.py:86
|
#: ema/views/ema.py:138
|
||||||
msgid "EMA {} added"
|
|
||||||
msgstr "EMA {} hinzugefügt"
|
|
||||||
|
|
||||||
#: ema/views/ema.py:223
|
|
||||||
msgid "EMA {} edited"
|
|
||||||
msgstr "EMA {} bearbeitet"
|
|
||||||
|
|
||||||
#: ema/views/ema.py:262
|
|
||||||
msgid "EMA removed"
|
msgid "EMA removed"
|
||||||
msgstr "EMA entfernt"
|
msgstr "EMA entfernt"
|
||||||
|
|
||||||
@ -1429,7 +1430,7 @@ msgstr "Datum Bestandskraft bzw. Rechtskraft"
|
|||||||
|
|
||||||
#: intervention/forms/intervention.py:216
|
#: intervention/forms/intervention.py:216
|
||||||
#: intervention/tests/unit/test_forms.py:36
|
#: intervention/tests/unit/test_forms.py:36
|
||||||
#: intervention/views/intervention.py:105
|
#: intervention/views/intervention.py:51
|
||||||
msgid "New intervention"
|
msgid "New intervention"
|
||||||
msgstr "Neuer Eingriff"
|
msgstr "Neuer Eingriff"
|
||||||
|
|
||||||
@ -1665,19 +1666,15 @@ msgstr ""
|
|||||||
msgid "Check performed"
|
msgid "Check performed"
|
||||||
msgstr "Prüfung durchgeführt"
|
msgstr "Prüfung durchgeführt"
|
||||||
|
|
||||||
#: intervention/views/intervention.py:57
|
#: intervention/views/intervention.py:33
|
||||||
msgid "Interventions - Overview"
|
msgid "Interventions - Overview"
|
||||||
msgstr "Eingriffe - Übersicht"
|
msgstr "Eingriffe - Übersicht"
|
||||||
|
|
||||||
#: intervention/views/intervention.py:90
|
#: intervention/views/intervention.py:154
|
||||||
msgid "Intervention {} added"
|
|
||||||
msgstr "Eingriff {} hinzugefügt"
|
|
||||||
|
|
||||||
#: intervention/views/intervention.py:236
|
|
||||||
msgid "Intervention {} edited"
|
msgid "Intervention {} edited"
|
||||||
msgstr "Eingriff {} bearbeitet"
|
msgstr "Eingriff {} bearbeitet"
|
||||||
|
|
||||||
#: intervention/views/intervention.py:278
|
#: intervention/views/intervention.py:204
|
||||||
msgid "{} removed"
|
msgid "{} removed"
|
||||||
msgstr "{} entfernt"
|
msgstr "{} entfernt"
|
||||||
|
|
||||||
@ -1689,7 +1686,7 @@ msgstr "Hierfür müssen Sie Mitarbeiter sein!"
|
|||||||
msgid "You need to be administrator to perform this action!"
|
msgid "You need to be administrator to perform this action!"
|
||||||
msgstr "Hierfür müssen Sie Administrator sein!"
|
msgstr "Hierfür müssen Sie Administrator sein!"
|
||||||
|
|
||||||
#: konova/decorators.py:65
|
#: konova/decorators.py:65 konova/utils/general.py:40
|
||||||
msgid ""
|
msgid ""
|
||||||
"+++ Attention: You are not part of any group. You won't be able to create, "
|
"+++ Attention: You are not part of any group. You won't be able to create, "
|
||||||
"edit or do anything. Please contact an administrator. +++"
|
"edit or do anything. Please contact an administrator. +++"
|
||||||
@ -1801,7 +1798,7 @@ msgstr "Sucht nach Einträgen, an denen diese Person gearbeitet hat"
|
|||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Speichern"
|
msgstr "Speichern"
|
||||||
|
|
||||||
#: konova/forms/base_form.py:72
|
#: konova/forms/base_form.py:74
|
||||||
msgid "Not editable"
|
msgid "Not editable"
|
||||||
msgstr "Nicht editierbar"
|
msgstr "Nicht editierbar"
|
||||||
|
|
||||||
@ -1810,7 +1807,7 @@ msgstr "Nicht editierbar"
|
|||||||
msgid "Geometry"
|
msgid "Geometry"
|
||||||
msgstr "Geometrie"
|
msgstr "Geometrie"
|
||||||
|
|
||||||
#: konova/forms/geometry_form.py:100
|
#: konova/forms/geometry_form.py:101
|
||||||
msgid "Only surfaces allowed. Points or lines must be buffered."
|
msgid "Only surfaces allowed. Points or lines must be buffered."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Nur Flächen erlaubt. Punkte oder Linien müssen zu Flächen gepuffert werden."
|
"Nur Flächen erlaubt. Punkte oder Linien müssen zu Flächen gepuffert werden."
|
||||||
@ -2268,8 +2265,9 @@ msgid ""
|
|||||||
"too small to be valid). These parts have been removed. Please check the "
|
"too small to be valid). These parts have been removed. Please check the "
|
||||||
"stored geometry."
|
"stored geometry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Die Geometrie enthielt {} invalide Bestandteile (z.B. unaussagekräftige Kleinstflächen)."
|
"Die Geometrie enthielt {} invalide Bestandteile (z.B. unaussagekräftige "
|
||||||
"Diese Bestandteile wurden automatisch entfernt. Bitte überprüfen Sie die angepasste Geometrie."
|
"Kleinstflächen).Diese Bestandteile wurden automatisch entfernt. Bitte "
|
||||||
|
"überprüfen Sie die angepasste Geometrie."
|
||||||
|
|
||||||
#: konova/utils/message_templates.py:89
|
#: konova/utils/message_templates.py:89
|
||||||
msgid "This intervention has {} revocations"
|
msgid "This intervention has {} revocations"
|
||||||
@ -2310,7 +2308,15 @@ msgstr ""
|
|||||||
"Dieses Datum ist unrealistisch. Geben Sie bitte das korrekte Datum ein "
|
"Dieses Datum ist unrealistisch. Geben Sie bitte das korrekte Datum ein "
|
||||||
"(>1950)."
|
"(>1950)."
|
||||||
|
|
||||||
#: konova/views/home.py:75 templates/navbars/navbar.html:16
|
#: konova/views/base.py:209
|
||||||
|
msgid "{} added"
|
||||||
|
msgstr "{} hinzugefügt"
|
||||||
|
|
||||||
|
#: konova/views/base.py:281
|
||||||
|
msgid "{} edited"
|
||||||
|
msgstr "{} bearbeitet"
|
||||||
|
|
||||||
|
#: konova/views/home.py:72 templates/navbars/navbar.html:16
|
||||||
msgid "Home"
|
msgid "Home"
|
||||||
msgstr "Home"
|
msgstr "Home"
|
||||||
|
|
||||||
@ -2330,6 +2336,10 @@ msgstr "{} verzeichnet"
|
|||||||
msgid "Errors found:"
|
msgid "Errors found:"
|
||||||
msgstr "Fehler gefunden:"
|
msgstr "Fehler gefunden:"
|
||||||
|
|
||||||
|
#: konova/views/report.py:21
|
||||||
|
msgid "Report {}"
|
||||||
|
msgstr "Bericht {}"
|
||||||
|
|
||||||
#: konova/views/resubmission.py:39
|
#: konova/views/resubmission.py:39
|
||||||
msgid "Resubmission set"
|
msgid "Resubmission set"
|
||||||
msgstr "Wiedervorlage gesetzt"
|
msgstr "Wiedervorlage gesetzt"
|
||||||
@ -3056,7 +3066,7 @@ msgid "Manage teams"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: user/templates/user/index.html:53 user/templates/user/team/index.html:19
|
#: user/templates/user/index.html:53 user/templates/user/team/index.html:19
|
||||||
#: user/views/views.py:135
|
#: user/views/views.py:134
|
||||||
msgid "Teams"
|
msgid "Teams"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3116,34 +3126,40 @@ msgstr "Läuft ab am"
|
|||||||
msgid "User API token"
|
msgid "User API token"
|
||||||
msgstr "API Nutzer Token"
|
msgstr "API Nutzer Token"
|
||||||
|
|
||||||
#: user/views/views.py:33
|
#: user/views/views.py:31
|
||||||
msgid "User settings"
|
msgid "User settings"
|
||||||
msgstr "Einstellungen"
|
msgstr "Einstellungen"
|
||||||
|
|
||||||
#: user/views/views.py:59
|
#: user/views/views.py:44
|
||||||
msgid "Notifications edited"
|
|
||||||
msgstr "Benachrichtigungen bearbeitet"
|
|
||||||
|
|
||||||
#: user/views/views.py:71
|
|
||||||
msgid "User notifications"
|
msgid "User notifications"
|
||||||
msgstr "Benachrichtigungen"
|
msgstr "Benachrichtigungen"
|
||||||
|
|
||||||
#: user/views/views.py:147
|
#: user/views/views.py:64
|
||||||
|
msgid "Notifications edited"
|
||||||
|
msgstr "Benachrichtigungen bearbeitet"
|
||||||
|
|
||||||
|
#: user/views/views.py:152
|
||||||
msgid "New team added"
|
msgid "New team added"
|
||||||
msgstr "Neues Team hinzugefügt"
|
msgstr "Neues Team hinzugefügt"
|
||||||
|
|
||||||
#: user/views/views.py:162
|
#: user/views/views.py:167
|
||||||
msgid "Team edited"
|
msgid "Team edited"
|
||||||
msgstr "Team bearbeitet"
|
msgstr "Team bearbeitet"
|
||||||
|
|
||||||
#: user/views/views.py:177
|
#: user/views/views.py:182
|
||||||
msgid "Team removed"
|
msgid "Team removed"
|
||||||
msgstr "Team gelöscht"
|
msgstr "Team gelöscht"
|
||||||
|
|
||||||
#: user/views/views.py:192
|
#: user/views/views.py:197
|
||||||
msgid "You are not a member of this team"
|
msgid "You are not a member of this team"
|
||||||
msgstr "Sie sind kein Mitglied dieses Teams"
|
msgstr "Sie sind kein Mitglied dieses Teams"
|
||||||
|
|
||||||
#: user/views/views.py:199
|
#: user/views/views.py:204
|
||||||
msgid "Left Team"
|
msgid "Left Team"
|
||||||
msgstr "Team verlassen"
|
msgstr "Team verlassen"
|
||||||
|
|
||||||
|
#~ msgid "EMA {} added"
|
||||||
|
#~ msgstr "EMA {} hinzugefügt"
|
||||||
|
|
||||||
|
#~ msgid "EMA {} edited"
|
||||||
|
#~ msgstr "EMA {} bearbeitet"
|
||||||
|
|||||||
@ -58,7 +58,7 @@
|
|||||||
[
|
[
|
||||||
{ "id": "webatlas_farbe", "folder": "bg", "type": "WMS", "order": -1, "title": "WebatlasRP farbig", "attribution": "LVermGeo", "url": "https://maps.service24.rlp.de/gisserver/services/RP/RP_WebAtlasRP/MapServer/WmsServer?", "name": "RP_WebAtlasRP", "active": true},
|
{ "id": "webatlas_farbe", "folder": "bg", "type": "WMS", "order": -1, "title": "WebatlasRP farbig", "attribution": "LVermGeo", "url": "https://maps.service24.rlp.de/gisserver/services/RP/RP_WebAtlasRP/MapServer/WmsServer?", "name": "RP_WebAtlasRP", "active": true},
|
||||||
{ "id": "webatlas_grau", "folder": "bg", "type": "WMS", "order": -1, "title": "WebatlasRP grau", "attribution": "LVermGeo", "url": "https://maps.service24.rlp.de/gisserver/services/RP/RP_ETRS_Gt/MapServer/WmsServer?", "name": "0", "active": false },
|
{ "id": "webatlas_grau", "folder": "bg", "type": "WMS", "order": -1, "title": "WebatlasRP grau", "attribution": "LVermGeo", "url": "https://maps.service24.rlp.de/gisserver/services/RP/RP_ETRS_Gt/MapServer/WmsServer?", "name": "0", "active": false },
|
||||||
{ "id": "luftbilder", "folder": "bg", "type": "WMS", "order": -1, "title": "Luftbilder", "attribution": "LVermGeo", "url": "https://geo4.service24.rlp.de/wms/rp_dop20.fcgi?", "name": "rp_dop20", "active": false },
|
{ "id": "luftbilder", "folder": "bg", "type": "WMS", "order": -1, "title": "Luftbilder", "attribution": "LVermGeo", "url": "https://geo4.service24.rlp.de/wms/dop_basis.fcgi?", "name": "rp_dop", "active": false },
|
||||||
{ "id": "basemap_farbe", "folder": "bg", "type": "WMS", "order": -1, "title": "BasemapDE farbig", "attribution": "BKG", "url": "https://sgx.geodatenzentrum.de/wms_basemapde?", "name": "de_basemapde_web_raster_farbe", "active": false },
|
{ "id": "basemap_farbe", "folder": "bg", "type": "WMS", "order": -1, "title": "BasemapDE farbig", "attribution": "BKG", "url": "https://sgx.geodatenzentrum.de/wms_basemapde?", "name": "de_basemapde_web_raster_farbe", "active": false },
|
||||||
{ "id": "basemap_grau", "folder": "bg", "type": "WMS", "order": -1, "title": "BasemapDE grau", "attribution": "BKG", "url": "https://sgx.geodatenzentrum.de/wms_basemapde?", "name": "de_basemapde_web_raster_grau", "active": false },
|
{ "id": "basemap_grau", "folder": "bg", "type": "WMS", "order": -1, "title": "BasemapDE grau", "attribution": "BKG", "url": "https://sgx.geodatenzentrum.de/wms_basemapde?", "name": "de_basemapde_web_raster_grau", "active": false },
|
||||||
{ "id": "dtk_farbe", "folder": "bg", "type": "WMS", "order": -1, "title": "DTK5 farbig", "attribution": "LVermGeo", "url": "https://geo4.service24.rlp.de/wms/dtk5_rp.fcgi?", "name": "rp_dtk5", "active": false },
|
{ "id": "dtk_farbe", "folder": "bg", "type": "WMS", "order": -1, "title": "DTK5 farbig", "attribution": "LVermGeo", "url": "https://geo4.service24.rlp.de/wms/dtk5_rp.fcgi?", "name": "rp_dtk5", "active": false },
|
||||||
|
|||||||
8786
templates/map/client/dist/netgis.min.js
vendored
8786
templates/map/client/dist/netgis.min.js
vendored
File diff suppressed because it is too large
Load Diff
@ -56,7 +56,7 @@
|
|||||||
{% if user.is_staff or user.is_superuser %}
|
{% if user.is_staff or user.is_superuser %}
|
||||||
<a class="dropdown-item" target="_blank" href="{% url 'admin:index' %}">{% fa5_icon 'tools' %} {% trans 'Admin' %}</a>
|
<a class="dropdown-item" target="_blank" href="{% url 'admin:index' %}">{% fa5_icon 'tools' %} {% trans 'Admin' %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a class="dropdown-item" href="{% url 'user:index' %}">{% fa5_icon 'cogs' %} {% trans 'Settings' %}</a>
|
<a class="dropdown-item" href="{% url 'user:detail' %}">{% fa5_icon 'cogs' %} {% trans 'Settings' %}</a>
|
||||||
<a class="dropdown-item" href="{% url 'logout' %}">{% fa5_icon 'sign-out-alt' %} {% trans 'Logout' %}</a>
|
<a class="dropdown-item" href="{% url 'logout' %}">{% fa5_icon 'sign-out-alt' %} {% trans 'Logout' %}</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@ -22,6 +22,7 @@ class NewAPITokenModalForm(BaseModalForm):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.template = "modal/modal_form.html"
|
self.template = "modal/modal_form.html"
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
self.instance = self.user
|
||||||
self.form_title = _("Generate API Token")
|
self.form_title = _("Generate API Token")
|
||||||
|
|
||||||
self.form_caption = ""
|
self.form_caption = ""
|
||||||
|
|||||||
@ -38,7 +38,7 @@ class UserNotificationForm(BaseForm):
|
|||||||
self.form_title = _("Edit notifications")
|
self.form_title = _("Edit notifications")
|
||||||
self.form_caption = _("")
|
self.form_caption = _("")
|
||||||
self.action_url = reverse("user:notifications")
|
self.action_url = reverse("user:notifications")
|
||||||
self.cancel_redirect = reverse("user:index")
|
self.cancel_redirect = reverse("user:detail")
|
||||||
|
|
||||||
# Insert all notifications into form field by creating choices as tuples
|
# Insert all notifications into form field by creating choices as tuples
|
||||||
notifications = UserNotification.objects.filter(
|
notifications = UserNotification.objects.filter(
|
||||||
|
|||||||
@ -26,7 +26,7 @@ class UserViewTestCase(BaseViewTestCase):
|
|||||||
self.team.users.add(self.superuser)
|
self.team.users.add(self.superuser)
|
||||||
self.team.admins.add(self.superuser)
|
self.team.admins.add(self.superuser)
|
||||||
# Prepare urls
|
# Prepare urls
|
||||||
self.index_url = reverse("user:index", args=())
|
self.index_url = reverse("user:detail", args=())
|
||||||
self.notification_url = reverse("user:notifications", args=())
|
self.notification_url = reverse("user:notifications", args=())
|
||||||
self.api_token_url = reverse("user:api-token", args=())
|
self.api_token_url = reverse("user:api-token", args=())
|
||||||
self.contact_url = reverse("user:contact", args=(self.superuser.id,))
|
self.contact_url = reverse("user:contact", args=(self.superuser.id,))
|
||||||
|
|||||||
@ -233,7 +233,7 @@ class UserNotificationFormTestCase(BaseTestCase):
|
|||||||
self.assertEqual(form.form_title, str(_("Edit notifications")))
|
self.assertEqual(form.form_title, str(_("Edit notifications")))
|
||||||
self.assertEqual(form.form_caption, "")
|
self.assertEqual(form.form_caption, "")
|
||||||
self.assertEqual(form.action_url, reverse("user:notifications"))
|
self.assertEqual(form.action_url, reverse("user:notifications"))
|
||||||
self.assertEqual(form.cancel_redirect, reverse("user:index"))
|
self.assertEqual(form.cancel_redirect, reverse("user:detail"))
|
||||||
|
|
||||||
def test_save(self):
|
def test_save(self):
|
||||||
selected_notification = UserNotification.objects.first()
|
selected_notification = UserNotification.objects.first()
|
||||||
@ -260,7 +260,7 @@ class ApiTokenFormTestCase(BaseTestCase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.assertIsNone(self.user.api_token)
|
self.assertIsNone(self.user.api_token)
|
||||||
form = NewAPITokenModalForm(request.POST, instance=self.user)
|
form = NewAPITokenModalForm(request.POST, request=request)
|
||||||
form.save()
|
form.save()
|
||||||
self.user.refresh_from_db()
|
self.user.refresh_from_db()
|
||||||
token = self.user.api_token
|
token = self.user.api_token
|
||||||
|
|||||||
26
user/urls.py
26
user/urls.py
@ -9,24 +9,26 @@ from django.urls import path
|
|||||||
|
|
||||||
from user.autocomplete.share import ShareUserAutocomplete, ShareTeamAutocomplete
|
from user.autocomplete.share import ShareUserAutocomplete, ShareTeamAutocomplete
|
||||||
from user.autocomplete.team import TeamAdminAutocomplete
|
from user.autocomplete.team import TeamAdminAutocomplete
|
||||||
from user.views.api_token import APITokenView, new_api_token_view
|
from user.views.api_token import APITokenView, NewAPITokenView
|
||||||
from user.views.propagate import PropagateUserView
|
from user.views.propagate import PropagateUserView
|
||||||
from user.views.views import *
|
from user.views.teams import TeamIndexView, NewTeamView, TeamDetailModalView, EditTeamView, RemoveTeamView, \
|
||||||
|
LeaveTeamView
|
||||||
|
from user.views.users import UserDetailView, NotificationsView, ContactView
|
||||||
|
|
||||||
app_name = "user"
|
app_name = "user"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", index_view, name="index"),
|
path("", UserDetailView.as_view(), name="detail"),
|
||||||
path("propagate/", PropagateUserView.as_view(), name="propagate"),
|
path("propagate/", PropagateUserView.as_view(), name="propagate"),
|
||||||
path("notifications/", notifications_view, name="notifications"),
|
path("notifications/", NotificationsView.as_view(), name="notifications"),
|
||||||
path("token/api", APITokenView.as_view(), name="api-token"),
|
path("token/api", APITokenView.as_view(), name="api-token"),
|
||||||
path("token/api/new", new_api_token_view, name="api-token-new"),
|
path("token/api/new", NewAPITokenView.as_view(), name="api-token-new"),
|
||||||
path("contact/<id>", contact_view, name="contact"),
|
path("contact/<id>", ContactView.as_view(), name="contact"),
|
||||||
path("team/", index_team_view, name="team-index"),
|
path("team/", TeamIndexView.as_view(), name="team-index"),
|
||||||
path("team/new", new_team_view, name="team-new"),
|
path("team/new", NewTeamView.as_view(), name="team-new"),
|
||||||
path("team/<id>", data_team_view, name="team-data"),
|
path("team/<id>", TeamDetailModalView.as_view(), name="team-data"),
|
||||||
path("team/<id>/edit", edit_team_view, name="team-edit"),
|
path("team/<id>/edit", EditTeamView.as_view(), name="team-edit"),
|
||||||
path("team/<id>/remove", remove_team_view, name="team-remove"),
|
path("team/<id>/remove", RemoveTeamView.as_view(), name="team-remove"),
|
||||||
path("team/<id>/leave", leave_team_view, name="team-leave"),
|
path("team/<id>/leave", LeaveTeamView.as_view(), name="team-leave"),
|
||||||
|
|
||||||
# Autocomplete urls
|
# Autocomplete urls
|
||||||
path("atcmplt/share/u", ShareUserAutocomplete.as_view(), name="share-user-autocomplete"),
|
path("atcmplt/share/u", ShareUserAutocomplete.as_view(), name="share-user-autocomplete"),
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user