# Renaming

* renames certain classes to match their content
* splits larger files into smaller ones
This commit is contained in:
mpeltriaux 2025-12-12 14:13:24 +01:00
parent c4cd40913d
commit e49eed21da
32 changed files with 705 additions and 815 deletions

View File

@ -237,7 +237,11 @@ class EditEcoAccountForm(NewEcoAccountForm):
class RemoveEcoAccountModalForm(RemoveModalForm): class RemoveEcoAccountModalForm(RemoveModalForm):
""" Form class
Provides a form for deleting eco accounts
"""
def is_valid(self): def is_valid(self):
super_valid = super().is_valid() super_valid = super().is_valid()
has_deductions = self.instance.deductions.exists() has_deductions = self.instance.deductions.exists()

View File

@ -6,29 +6,26 @@ 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.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpRequest, JsonResponse from django.shortcuts import get_object_or_404, 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 compensation.forms.compensation import EditCompensationForm, NewCompensationForm from compensation.forms.compensation import EditCompensationForm, NewCompensationForm
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.decorators import shared_access_required, default_group_required, login_required_modal
from konova.forms.modals import RemoveModalForm from konova.forms.modals import RemoveModalForm
from konova.utils.message_templates import COMPENSATION_REMOVED_TEMPLATE, DATA_CHECKED_PREVIOUSLY_TEMPLATE, \ from konova.utils.message_templates import DATA_CHECKED_PREVIOUSLY_TEMPLATE, \
RECORDED_BLOCKS_EDIT, PARAMS_INVALID RECORDED_BLOCKS_EDIT, PARAMS_INVALID
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView, BaseNewSpatialLocatedObjectFormView, \ from konova.views.identifier import AbstractIdentifierGeneratorView
BaseEditSpatialLocatedObjectFormView from konova.views.form import AbstractNewGeometryFormView, AbstractEditGeometryFormView
from konova.views.index import AbstractIndexView
from konova.views.detail import BaseDetailView from konova.views.detail import BaseDetailView
from konova.views.remove import BaseRemoveModalFormView from konova.views.remove import BaseRemoveModalFormView
class CompensationIndexView(LoginRequiredMixin, BaseIndexView): class CompensationIndexView(LoginRequiredMixin, AbstractIndexView):
_TAB_TITLE = _("Compensations - Overview") _TAB_TITLE = _("Compensations - Overview")
_INDEX_TABLE_CLS = CompensationTable _INDEX_TABLE_CLS = CompensationTable
@ -42,7 +39,7 @@ class CompensationIndexView(LoginRequiredMixin, BaseIndexView):
return qs return qs
class NewCompensationFormView(BaseNewSpatialLocatedObjectFormView): class NewCompensationFormView(AbstractNewGeometryFormView):
_FORM_CLS = NewCompensationForm _FORM_CLS = NewCompensationForm
_MODEL_CLS = Compensation _MODEL_CLS = Compensation
_TEMPLATE = "compensation/form/view.html" _TEMPLATE = "compensation/form/view.html"
@ -82,7 +79,7 @@ class NewCompensationFormView(BaseNewSpatialLocatedObjectFormView):
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
class EditCompensationFormView(BaseEditSpatialLocatedObjectFormView): class EditCompensationFormView(AbstractEditGeometryFormView):
_MODEL_CLS = Compensation _MODEL_CLS = Compensation
_FORM_CLS = EditCompensationForm _FORM_CLS = EditCompensationForm
_TEMPLATE = "compensation/form/view.html" _TEMPLATE = "compensation/form/view.html"
@ -93,7 +90,7 @@ class EditCompensationFormView(BaseEditSpatialLocatedObjectFormView):
return user.is_default_user() return user.is_default_user()
class CompensationIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): class CompensationIdentifierGeneratorView(LoginRequiredMixin, AbstractIdentifierGeneratorView):
_MODEL_CLS = Compensation _MODEL_CLS = Compensation
_REDIRECT_URL = "compensation:index" _REDIRECT_URL = "compensation:index"

View File

@ -10,10 +10,10 @@ from django.urls import reverse
from compensation.models import Compensation from compensation.models import Compensation
from konova.sub_settings.django_settings import BASE_URL from konova.sub_settings.django_settings import BASE_URL
from konova.utils.qrcode import QrCode from konova.utils.qrcode import QrCode
from konova.views.report import BaseReportView from konova.views.report import AbstractReportView
class BaseCompensationReportView(BaseReportView): class BaseCompensationReportView(AbstractReportView):
def _get_compensation_report_context(self, obj): def _get_compensation_report_context(self, obj):
# Order states by surface # Order states by surface
before_states = obj.before_states.all().order_by("-surface").prefetch_related("biotope_type") before_states = obj.before_states.all().order_by("-surface").prefetch_related("biotope_type")

View File

@ -5,31 +5,24 @@ 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.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin 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, redirect, render
from django.urls import reverse
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from compensation.forms.eco_account import EditEcoAccountForm, NewEcoAccountForm, RemoveEcoAccountModalForm from compensation.forms.eco_account import EditEcoAccountForm, NewEcoAccountForm, RemoveEcoAccountModalForm
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.views.identifier import AbstractIdentifierGeneratorView
from konova.decorators import shared_access_required, default_group_required, login_required_modal from konova.views.form import AbstractNewGeometryFormView, AbstractEditGeometryFormView
from konova.forms import SimpleGeomForm from konova.views.index import AbstractIndexView
from konova.settings import ETS_GROUP
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, \
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.detail import BaseDetailView
from konova.views.remove import BaseRemoveModalFormView from konova.views.remove import BaseRemoveModalFormView
class EcoAccountIndexView(LoginRequiredMixin, BaseIndexView): class EcoAccountIndexView(LoginRequiredMixin, AbstractIndexView):
""" View class for indexing eco accounts
"""
_INDEX_TABLE_CLS = EcoAccountTable _INDEX_TABLE_CLS = EcoAccountTable
_TAB_TITLE = _("Eco-account - Overview") _TAB_TITLE = _("Eco-account - Overview")
@ -42,7 +35,12 @@ class EcoAccountIndexView(LoginRequiredMixin, BaseIndexView):
return qs return qs
class NewEcoAccountFormView(BaseNewSpatialLocatedObjectFormView): class NewEcoAccountFormView(AbstractNewGeometryFormView):
""" Form view class
Renders a form for new eco accounts
"""
_FORM_CLS = NewEcoAccountForm _FORM_CLS = NewEcoAccountForm
_MODEL_CLS = EcoAccount _MODEL_CLS = EcoAccount
_TEMPLATE = "compensation/form/view.html" _TEMPLATE = "compensation/form/view.html"
@ -54,7 +52,12 @@ class NewEcoAccountFormView(BaseNewSpatialLocatedObjectFormView):
return user.is_default_user() return user.is_default_user()
class EditEcoAccountFormView(BaseEditSpatialLocatedObjectFormView): class EditEcoAccountFormView(AbstractEditGeometryFormView):
""" Form view class
Renders a form for editing of eco accounts
"""
_FORM_CLS = EditEcoAccountForm _FORM_CLS = EditEcoAccountForm
_MODEL_CLS = EcoAccount _MODEL_CLS = EcoAccount
_TEMPLATE = "compensation/form/view.html" _TEMPLATE = "compensation/form/view.html"
@ -65,129 +68,20 @@ class EditEcoAccountFormView(BaseEditSpatialLocatedObjectFormView):
return user.is_default_user() return user.is_default_user()
@login_required class EcoAccountIdentifierGeneratorView(LoginRequiredMixin, AbstractIdentifierGeneratorView):
@default_group_required """ View class for identifier generation on eco accounts
def new_view(request: HttpRequest):
"""
Renders a view for a new eco account creation
Args:
request (HttpRequest): The incoming request
Returns:
""" """
template = "compensation/form/view.html"
data_form = NewEcoAccountForm(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)
acc = data_form.save(request.user, geom_form)
if generated_identifier != acc.identifier:
messages.info(
request,
IDENTIFIER_REPLACED.format(
generated_identifier,
acc.identifier
)
)
messages.success(request, _("Eco-Account {} added").format(acc.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:acc:detail", id=acc.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 Eco-Account"),
}
context = BaseContext(request, context).context
return render(request, template, context)
class EcoAccountIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
_MODEL_CLS = EcoAccount _MODEL_CLS = EcoAccount
_REDIRECT_URL = "compensation:acc:index" _REDIRECT_URL = "compensation:acc:index"
@login_required
@default_group_required
@shared_access_required(EcoAccount, "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
acc = get_object_or_404(EcoAccount, id=id)
if acc.is_recorded:
messages.info(
request,
RECORDED_BLOCKS_EDIT
)
return redirect("compensation:acc:detail", id=id)
# Create forms, initialize with values from db/from POST request
data_form = EditEcoAccountForm(request.POST or None, instance=acc)
geom_form = SimpleGeomForm(request.POST or None, read_only=False, instance=acc)
if request.method == "POST":
data_form_valid = data_form.is_valid()
geom_form_valid = geom_form.is_valid()
if data_form_valid and geom_form_valid:
# The data form takes the geom form for processing, as well as the performing user
acc = data_form.save(request.user, geom_form)
messages.success(request, _("Eco-Account {} edited").format(acc.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:acc:detail", id=acc.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(acc.identifier),
}
context = BaseContext(request, context).context
return render(request, template, context)
class EcoAccountDetailView(BaseDetailView): class EcoAccountDetailView(BaseDetailView):
""" Detail view class
Renders details of an eco account
"""
_MODEL_CLS = EcoAccount _MODEL_CLS = EcoAccount
_TEMPLATE = "compensation/detail/eco_account/view.html" _TEMPLATE = "compensation/detail/eco_account/view.html"
@ -256,6 +150,11 @@ class EcoAccountDetailView(BaseDetailView):
class RemoveEcoAccountView(LoginRequiredMixin, BaseRemoveModalFormView): class RemoveEcoAccountView(LoginRequiredMixin, BaseRemoveModalFormView):
""" Form view class
Renders a form for removing eco accounts
"""
_MODEL_CLS = EcoAccount _MODEL_CLS = EcoAccount
_FORM_CLS = RemoveEcoAccountModalForm _FORM_CLS = RemoveEcoAccountModalForm
_REDIRECT_URL = "compensation:acc:index" _REDIRECT_URL = "compensation:acc:index"

View File

@ -10,10 +10,10 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from compensation.forms.modals.payment import NewPaymentForm, RemovePaymentModalForm, EditPaymentModalForm from compensation.forms.modals.payment import NewPaymentForm, RemovePaymentModalForm, EditPaymentModalForm
from intervention.models import Intervention from intervention.models import Intervention
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 from konova.views.modal import AbstractModalFormView
class BasePaymentView(LoginRequiredMixin, BaseModalFormView): class BasePaymentView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = Intervention _MODEL_CLS = Intervention
_REDIRECT_URL = "intervention:detail" _REDIRECT_URL = "intervention:detail"

View File

@ -12,13 +12,14 @@ 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.views.base import BaseIndexView, BaseIdentifierGeneratorView, BaseNewSpatialLocatedObjectFormView, \ from konova.views.identifier import AbstractIdentifierGeneratorView
BaseEditSpatialLocatedObjectFormView from konova.views.form import AbstractNewGeometryFormView, AbstractEditGeometryFormView
from konova.views.index import AbstractIndexView
from konova.views.detail import BaseDetailView from konova.views.detail import BaseDetailView
from konova.views.remove import BaseRemoveModalFormView from konova.views.remove import BaseRemoveModalFormView
class EmaIndexView(LoginRequiredMixin, BaseIndexView): class EmaIndexView(LoginRequiredMixin, AbstractIndexView):
_TAB_TITLE = _("EMAs - Overview") _TAB_TITLE = _("EMAs - Overview")
_INDEX_TABLE_CLS = EmaTable _INDEX_TABLE_CLS = EmaTable
@ -31,7 +32,7 @@ class EmaIndexView(LoginRequiredMixin, BaseIndexView):
return qs return qs
class NewEmaFormView(BaseNewSpatialLocatedObjectFormView): class NewEmaFormView(AbstractNewGeometryFormView):
_FORM_CLS = NewEmaForm _FORM_CLS = NewEmaForm
_MODEL_CLS = Ema _MODEL_CLS = Ema
_TEMPLATE = "ema/form/view.html" _TEMPLATE = "ema/form/view.html"
@ -43,7 +44,7 @@ class NewEmaFormView(BaseNewSpatialLocatedObjectFormView):
return user.is_ets_user() return user.is_ets_user()
class EditEmaFormView(BaseEditSpatialLocatedObjectFormView): class EditEmaFormView(AbstractEditGeometryFormView):
_MODEL_CLS = Ema _MODEL_CLS = Ema
_FORM_CLS = EditEmaForm _FORM_CLS = EditEmaForm
_TEMPLATE = "ema/form/view.html" _TEMPLATE = "ema/form/view.html"
@ -55,7 +56,7 @@ class EditEmaFormView(BaseEditSpatialLocatedObjectFormView):
return user.is_ets_user() return user.is_ets_user()
class EmaIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): class EmaIdentifierGeneratorView(LoginRequiredMixin, AbstractIdentifierGeneratorView):
_MODEL_CLS = Ema _MODEL_CLS = Ema
_REDIRECT_URL = "ema:index" _REDIRECT_URL = "ema:index"

View File

@ -10,10 +10,10 @@ 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.views.base import BaseModalFormView from konova.views.modal import AbstractModalFormView
class InterventionCheckView(LoginRequiredMixin, BaseModalFormView): class InterventionCheckView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = Intervention _MODEL_CLS = Intervention
_FORM_CLS = CheckModalForm _FORM_CLS = CheckModalForm
_MSG_SUCCESS = _("Check performed") _MSG_SUCCESS = _("Check performed")

View File

@ -5,29 +5,22 @@ 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.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin 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, render, redirect
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.utils.message_templates import DATA_CHECKED_PREVIOUSLY_TEMPLATE
from konova.decorators import default_group_required, shared_access_required from konova.views.identifier import AbstractIdentifierGeneratorView
from konova.forms import SimpleGeomForm from konova.views.form import AbstractNewGeometryFormView, AbstractEditGeometryFormView
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER from konova.views.index import AbstractIndexView
from konova.utils.message_templates import DATA_CHECKED_PREVIOUSLY_TEMPLATE, RECORDED_BLOCKS_EDIT, \
CHECK_STATE_RESET, FORM_INVALID, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView, BaseNewSpatialLocatedObjectFormView, \
BaseEditSpatialLocatedObjectFormView
from konova.views.detail import BaseDetailView from konova.views.detail import BaseDetailView
from konova.views.remove import BaseRemoveModalFormView from konova.views.remove import BaseRemoveModalFormView
class InterventionIndexView(LoginRequiredMixin, BaseIndexView): class InterventionIndexView(LoginRequiredMixin, AbstractIndexView):
_INDEX_TABLE_CLS = InterventionTable _INDEX_TABLE_CLS = InterventionTable
_TAB_TITLE = _("Interventions - Overview") _TAB_TITLE = _("Interventions - Overview")
@ -42,7 +35,7 @@ class InterventionIndexView(LoginRequiredMixin, BaseIndexView):
return qs return qs
class NewInterventionFormView(BaseNewSpatialLocatedObjectFormView): class NewInterventionFormView(AbstractNewGeometryFormView):
_MODEL_CLS = Intervention _MODEL_CLS = Intervention
_FORM_CLS = NewInterventionForm _FORM_CLS = NewInterventionForm
_TEMPLATE = "intervention/form/view.html" _TEMPLATE = "intervention/form/view.html"
@ -50,7 +43,7 @@ class NewInterventionFormView(BaseNewSpatialLocatedObjectFormView):
_TAB_TITLE = _("New intervention") _TAB_TITLE = _("New intervention")
class EditInterventionFormView(BaseEditSpatialLocatedObjectFormView): class EditInterventionFormView(AbstractEditGeometryFormView):
_MODEL_CLS = Intervention _MODEL_CLS = Intervention
_FORM_CLS = EditInterventionForm _FORM_CLS = EditInterventionForm
_TEMPLATE = "intervention/form/view.html" _TEMPLATE = "intervention/form/view.html"
@ -58,7 +51,7 @@ class EditInterventionFormView(BaseEditSpatialLocatedObjectFormView):
_TAB_TITLE = _("Edit {}") _TAB_TITLE = _("Edit {}")
class InterventionIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): class InterventionIdentifierGeneratorView(LoginRequiredMixin, AbstractIdentifierGeneratorView):
_MODEL_CLS = Intervention _MODEL_CLS = Intervention
_REDIRECT_URL = "intervention:index" _REDIRECT_URL = "intervention:index"
@ -117,69 +110,6 @@ class InterventionDetailView(BaseDetailView):
} }
return context return context
@login_required
@default_group_required
@shared_access_required(Intervention, "id")
def edit_view(request: HttpRequest, id: str):
"""
Renders a view for editing interventions
Args:
request (HttpRequest): The incoming request
Returns:
"""
template = "intervention/form/view.html"
# Get object from db
intervention = get_object_or_404(Intervention, id=id)
if intervention.is_recorded:
messages.info(
request,
RECORDED_BLOCKS_EDIT
)
return redirect("intervention:detail", id=id)
# Create forms, initialize with values from db/from POST request
data_form = EditInterventionForm(request.POST or None, instance=intervention)
geom_form = SimpleGeomForm(request.POST or None, read_only=False, instance=intervention)
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
# Save the current state of recorded|checked to inform the user in case of a status reset due to editing
intervention_is_checked = intervention.checked is not None
intervention = data_form.save(request.user, geom_form)
messages.success(request, _("Intervention {} edited").format(intervention.identifier))
if intervention_is_checked:
messages.info(request, CHECK_STATE_RESET)
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: _("Edit {}").format(intervention.identifier),
}
context = BaseContext(request, context).context
return render(request, template, context)
class RemoveInterventionView(LoginRequiredMixin, BaseRemoveModalFormView): class RemoveInterventionView(LoginRequiredMixin, BaseRemoveModalFormView):
_MODEL_CLS = Intervention _MODEL_CLS = Intervention
_REDIRECT_URL = "intervention:index" _REDIRECT_URL = "intervention:index"

View File

@ -10,10 +10,10 @@ from django.urls import reverse
from intervention.models import Intervention from intervention.models import Intervention
from konova.sub_settings.django_settings import BASE_URL from konova.sub_settings.django_settings import BASE_URL
from konova.utils.qrcode import QrCode from konova.utils.qrcode import QrCode
from konova.views.report import BaseReportView from konova.views.report import AbstractReportView
class InterventionReportView(BaseReportView): class InterventionReportView(AbstractReportView):
_TEMPLATE = 'intervention/report/report.html' _TEMPLATE = 'intervention/report/report.html'
_MODEL = Intervention _MODEL = Intervention

View File

@ -15,10 +15,10 @@ from intervention.forms.modals.revocation import NewRevocationModalForm, EditRev
from intervention.models import Intervention, RevocationDocument from intervention.models import Intervention, RevocationDocument
from konova.utils.documents import get_document from konova.utils.documents import get_document
from konova.utils.message_templates import DATA_UNSHARED, REVOCATION_EDITED, REVOCATION_REMOVED, REVOCATION_ADDED from konova.utils.message_templates import DATA_UNSHARED, REVOCATION_EDITED, REVOCATION_REMOVED, REVOCATION_ADDED
from konova.views.base import BaseModalFormView, BaseView from konova.views.modal import AbstractModalFormView, AbstractBaseView
class BaseRevocationView(LoginRequiredMixin, BaseModalFormView): class BaseRevocationView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = Intervention _MODEL_CLS = Intervention
_REDIRECT_URL = "intervention:detail" _REDIRECT_URL = "intervention:detail"
@ -48,7 +48,7 @@ class RemoveRevocationView(BaseRevocationView):
_MSG_SUCCESS = REVOCATION_REMOVED _MSG_SUCCESS = REVOCATION_REMOVED
class GetRevocationDocumentView(LoginRequiredMixin, BaseView): class GetRevocationDocumentView(LoginRequiredMixin, AbstractBaseView):
_MODEL_CLS = RevocationDocument _MODEL_CLS = RevocationDocument
_REDIRECT_URL = "intervention:detail" _REDIRECT_URL = "intervention:detail"

View File

@ -11,10 +11,10 @@ from compensation.forms.modals.compensation_action import NewCompensationActionM
EditCompensationActionModalForm, RemoveCompensationActionModalForm EditCompensationActionModalForm, RemoveCompensationActionModalForm
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 from konova.views.modal import AbstractModalFormView
class AbstractCompensationActionView(LoginRequiredMixin, BaseModalFormView): class AbstractCompensationActionView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = None _MODEL_CLS = None
_REDIRECT_URL = None _REDIRECT_URL = None

View File

@ -5,26 +5,16 @@ Created on: 15.10.25
""" """
from abc import abstractmethod from abc import abstractmethod
from bootstrap_modal_forms.mixins import is_ajax
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin from django.http import HttpRequest
from django.core.exceptions import ObjectDoesNotExist from django.shortcuts import redirect
from django.http import HttpRequest, JsonResponse, HttpResponseRedirect
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse from django.urls import reverse
from django.views import View 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.general import check_user_is_in_any_group
from konova.utils.message_templates import MISSING_GROUP_PERMISSION, DATA_UNSHARED, IDENTIFIER_REPLACED, \ from konova.utils.message_templates import MISSING_GROUP_PERMISSION, DATA_UNSHARED
GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE, RECORDED_BLOCKS_EDIT, FORM_INVALID
class BaseView(View): class AbstractBaseView(View):
""" An abstract base 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 This class represents the root of all views on this project. It defines private variables which have to be used
@ -123,519 +113,3 @@ class BaseView(View):
""" """
return self._REDIRECT_URL_ERROR 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()

View File

@ -10,10 +10,10 @@ from django.contrib.auth.mixins import LoginRequiredMixin
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.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 from konova.views.modal import AbstractModalFormView
class AbstractNewDeadlineView(LoginRequiredMixin, BaseModalFormView): class AbstractNewDeadlineView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = None _MODEL_CLS = None
_FORM_CLS = NewDeadlineModalForm _FORM_CLS = NewDeadlineModalForm
_REDIRECT_URL = None _REDIRECT_URL = None
@ -29,7 +29,7 @@ class AbstractNewDeadlineView(LoginRequiredMixin, BaseModalFormView):
return user.is_default_user() return user.is_default_user()
class AbstractEditDeadlineView(LoginRequiredMixin, BaseModalFormView): class AbstractEditDeadlineView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = None _MODEL_CLS = None
_FORM_CLS = EditDeadlineModalForm _FORM_CLS = EditDeadlineModalForm
_REDIRECT_URL = None _REDIRECT_URL = None
@ -45,7 +45,7 @@ class AbstractEditDeadlineView(LoginRequiredMixin, BaseModalFormView):
return user.is_default_user() return user.is_default_user()
class AbstractRemoveDeadlineView(LoginRequiredMixin, BaseModalFormView): class AbstractRemoveDeadlineView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = None _MODEL_CLS = None
_FORM_CLS = RemoveDeadlineModalForm _FORM_CLS = RemoveDeadlineModalForm
_REDIRECT_URL = None _REDIRECT_URL = None

View File

@ -11,10 +11,10 @@ from django.urls import reverse
from intervention.forms.modals.deduction import NewEcoAccountDeductionModalForm, EditEcoAccountDeductionModalForm, \ from intervention.forms.modals.deduction import NewEcoAccountDeductionModalForm, EditEcoAccountDeductionModalForm, \
RemoveEcoAccountDeductionModalForm RemoveEcoAccountDeductionModalForm
from konova.utils.general import check_id_is_valid_uuid from konova.utils.general import check_id_is_valid_uuid
from konova.views.base import BaseModalFormView from konova.views.modal import AbstractModalFormView
class AbstractDeductionView(BaseModalFormView): class AbstractDeductionView(AbstractModalFormView):
_REDIRECT_URL = None _REDIRECT_URL = None
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):

View File

@ -16,10 +16,10 @@ 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.general import check_id_is_valid_uuid from konova.utils.general import check_id_is_valid_uuid
from konova.utils.message_templates import DO_NOT_FORGET_TO_SHARE from konova.utils.message_templates import DO_NOT_FORGET_TO_SHARE
from konova.views.base import BaseView from konova.views.base import AbstractBaseView
class BaseDetailView(LoginRequiredMixin, BaseView): class BaseDetailView(LoginRequiredMixin, AbstractBaseView):
_MODEL_CLS = None _MODEL_CLS = None
class Meta: class Meta:

View File

@ -12,10 +12,10 @@ from django.shortcuts import get_object_or_404
from konova.forms.modals import EditDocumentModalForm from konova.forms.modals import EditDocumentModalForm
from konova.utils.documents import get_document from konova.utils.documents import get_document
from konova.utils.message_templates import DOCUMENT_ADDED, DOCUMENT_EDITED, DOCUMENT_REMOVED_TEMPLATE from konova.utils.message_templates import DOCUMENT_ADDED, DOCUMENT_EDITED, DOCUMENT_REMOVED_TEMPLATE
from konova.views.base import BaseModalFormView, BaseView from konova.views.modal import AbstractModalFormView, AbstractBaseView
class AbstractNewDocumentView(LoginRequiredMixin, BaseModalFormView): class AbstractNewDocumentView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = None _MODEL_CLS = None
_FORM_CLS = None _FORM_CLS = None
_REDIRECT_URL = None _REDIRECT_URL = None
@ -31,7 +31,7 @@ class AbstractNewDocumentView(LoginRequiredMixin, BaseModalFormView):
return user.is_default_user() return user.is_default_user()
class AbstractGetDocumentView(LoginRequiredMixin, BaseView): class AbstractGetDocumentView(LoginRequiredMixin, AbstractBaseView):
_MODEL_CLS = None _MODEL_CLS = None
_DOCUMENT_CLS = None _DOCUMENT_CLS = None
@ -68,7 +68,7 @@ class AbstractGetDocumentView(LoginRequiredMixin, BaseView):
return obj.is_shared_with(user) return obj.is_shared_with(user)
class AbstractRemoveDocumentView(LoginRequiredMixin, BaseModalFormView): class AbstractRemoveDocumentView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = None _MODEL_CLS = None
_DOCUMENT_CLS = None _DOCUMENT_CLS = None
_FORM_CLS = None _FORM_CLS = None
@ -90,7 +90,7 @@ class AbstractRemoveDocumentView(LoginRequiredMixin, BaseModalFormView):
return self._MSG_SUCCESS.format(doc.title) return self._MSG_SUCCESS.format(doc.title)
class AbstractEditDocumentView(LoginRequiredMixin, BaseModalFormView): class AbstractEditDocumentView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = None _MODEL_CLS = None
_DOCUMENT_CLS = None _DOCUMENT_CLS = None
_FORM_CLS = EditDocumentModalForm _FORM_CLS = EditDocumentModalForm

282
konova/views/form.py Normal file
View File

@ -0,0 +1,282 @@
"""
Author: Michel Peltriaux
Created on: 12.12.25
"""
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpRequest
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from konova.contexts import BaseContext
from konova.forms import BaseForm, SimpleGeomForm
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.utils.message_templates import RECORDED_BLOCKS_EDIT, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE, \
FORM_INVALID, IDENTIFIER_REPLACED
from konova.views.base import AbstractBaseView
class AbstractFormView(AbstractBaseView):
""" 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 AbstractGeometryFormView(LoginRequiredMixin, AbstractFormView):
""" Abstract base view for processing objects with spatial data
"""
_GEOMETRY_FORM_CLS = SimpleGeomForm
class Meta:
abstract = True
class AbstractNewGeometryFormView(AbstractGeometryFormView):
""" 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 AbstractEditGeometryFormView(AbstractGeometryFormView):
""" 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()

View File

@ -15,10 +15,10 @@ 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 from konova.views.base import AbstractBaseView
class GeomParcelsView(BaseView): class GeomParcelsView(AbstractBaseView):
_TEMPLATE = "konova/includes/parcels/parcel_table_frame.html" _TEMPLATE = "konova/includes/parcels/parcel_table_frame.html"
def get(self, request: HttpRequest, id: str): def get(self, request: HttpRequest, id: str):
@ -114,7 +114,7 @@ class GeomParcelsView(BaseView):
return True return True
class GeomParcelsContentView(BaseView): class GeomParcelsContentView(AbstractBaseView):
_TEMPLATE = "konova/includes/parcels/parcel_table_content.html" _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):

View File

@ -15,11 +15,11 @@ 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.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 konova.views.base import AbstractBaseView
from news.models import ServerMessage from news.models import ServerMessage
class HomeView(LoginRequiredMixin, BaseView): class HomeView(LoginRequiredMixin, AbstractBaseView):
_TEMPLATE = "konova/home.html" _TEMPLATE = "konova/home.html"
def get(self, request: HttpRequest): def get(self, request: HttpRequest):

View File

@ -0,0 +1,55 @@
"""
Author: Michel Peltriaux
Created on: 12.12.25
"""
from django.http import HttpRequest, JsonResponse
from konova.views.base import AbstractBaseView
class AbstractIdentifierGeneratorView(AbstractBaseView):
""" View class
Process a request for generating a new identifier
"""
_MODEL_CLS = None
_REDIRECT_URL: str = "home"
class Meta:
abstract = True
def get(self, request: HttpRequest):
""" GET endpoint
Args:
request ():
Returns:
"""
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

65
konova/views/index.py Normal file
View File

@ -0,0 +1,65 @@
"""
Author: Michel Peltriaux
Created on: 12.12.25
"""
from abc import abstractmethod
from django.http import HttpRequest
from django.shortcuts import render
from konova.contexts import BaseContext
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.views.base import AbstractBaseView
class AbstractIndexView(AbstractBaseView):
""" Abstract base class for all 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

View File

@ -9,10 +9,10 @@ from django.shortcuts import get_object_or_404, render
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 from konova.views.base import AbstractBaseView
class AbstractLogView(BaseView): class AbstractLogView(AbstractBaseView):
_MODEL_CLS = None _MODEL_CLS = None
_TEMPLATE = "modal/modal_generic.html" _TEMPLATE = "modal/modal_generic.html"

183
konova/views/modal.py Normal file
View File

@ -0,0 +1,183 @@
"""
Author: Michel Peltriaux
Created on: 12.12.25
"""
from bootstrap_modal_forms.mixins import is_ajax
from django.contrib import messages
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpRequest, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from konova.contexts import BaseContext
from konova.models import BaseObject
from konova.views.base import AbstractBaseView
class AbstractModalFormView(AbstractBaseView):
""" 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 an object
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"

View File

@ -7,10 +7,10 @@ Created on: 19.08.22
""" """
from konova.forms.modals import RecordModalForm from konova.forms.modals import RecordModalForm
from konova.utils.message_templates import ENTRY_RECORDED, ENTRY_UNRECORDED from konova.utils.message_templates import ENTRY_RECORDED, ENTRY_UNRECORDED
from konova.views.base import BaseModalFormView from konova.views.modal import AbstractModalFormView
class AbstractRecordView(BaseModalFormView): class AbstractRecordView(AbstractModalFormView):
_MODEL_CLS = None _MODEL_CLS = None
_FORM_CLS = RecordModalForm _FORM_CLS = RecordModalForm
_MSG_SUCCESS = None _MSG_SUCCESS = None

View File

@ -7,11 +7,10 @@ from django.urls import reverse
from konova.forms.modals import RemoveModalForm from konova.forms.modals import RemoveModalForm
from konova.utils.message_templates import GENERIC_REMOVED_TEMPLATE from konova.utils.message_templates import GENERIC_REMOVED_TEMPLATE
from konova.views.base import BaseModalFormView from konova.views.modal import AbstractModalFormView
class BaseRemoveModalFormView(BaseModalFormView): class BaseRemoveModalFormView(AbstractModalFormView):
_MODEL_CLS = None
_FORM_CLS = RemoveModalForm _FORM_CLS = RemoveModalForm
_MSG_SUCCESS = GENERIC_REMOVED_TEMPLATE _MSG_SUCCESS = GENERIC_REMOVED_TEMPLATE
_REDIRECT_URL = None _REDIRECT_URL = None

View File

@ -13,10 +13,10 @@ from django.utils.translation import gettext_lazy as _
from konova.contexts import BaseContext from konova.contexts import BaseContext
from konova.forms import SimpleGeomForm from konova.forms import SimpleGeomForm
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 konova.views.base import AbstractBaseView
class BaseReportView(BaseView): class AbstractReportView(AbstractBaseView):
_TEMPLATE = None _TEMPLATE = None
_TAB_TITLE = _("Report {}") _TAB_TITLE = _("Report {}")
_MODEL = None _MODEL = None

View File

@ -8,10 +8,10 @@ Created on: 19.08.22
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from konova.utils.message_templates import NEW_RESUBMISSION_CREATED from konova.utils.message_templates import NEW_RESUBMISSION_CREATED
from konova.views.base import BaseModalFormView from konova.views.modal import AbstractModalFormView
class AbstractResubmissionView(LoginRequiredMixin, BaseModalFormView): class AbstractResubmissionView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = None _MODEL_CLS = None
_FORM_CLS = None _FORM_CLS = None
_REDIRECT_URL = None _REDIRECT_URL = None

View File

@ -12,10 +12,11 @@ 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 from konova.views.base import AbstractBaseView
from konova.views.modal import AbstractModalFormView
class AbstractShareByTokenView(LoginRequiredMixin, BaseView): class AbstractShareByTokenView(LoginRequiredMixin, AbstractBaseView):
_MODEL_CLS = None _MODEL_CLS = None
_REDIRECT_URL = None _REDIRECT_URL = None
@ -69,7 +70,7 @@ class AbstractShareByTokenView(LoginRequiredMixin, BaseView):
return True return True
class AbstractShareFormView(LoginRequiredMixin, BaseModalFormView): class AbstractShareFormView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = None _MODEL_CLS = None
_FORM_CLS = ShareModalForm _FORM_CLS = ShareModalForm
_MSG_SUCCESS = DATA_SHARE_SET _MSG_SUCCESS = DATA_SHARE_SET

View File

@ -12,10 +12,10 @@ from compensation.forms.modals.state import NewCompensationStateModalForm, EditC
RemoveCompensationStateModalForm RemoveCompensationStateModalForm
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 from konova.views.modal import AbstractModalFormView
class AbstractCompensationStateView(LoginRequiredMixin, BaseModalFormView): class AbstractCompensationStateView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = None _MODEL_CLS = None
_FORM_CLS = None _FORM_CLS = None
_REDIRECT_URL = None _REDIRECT_URL = None

View File

@ -15,7 +15,7 @@ from konova.contexts import BaseContext
from konova.decorators import default_group_required from konova.decorators import default_group_required
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 NEW_API_TOKEN_GENERATED from konova.utils.message_templates import NEW_API_TOKEN_GENERATED
from konova.views.base import BaseModalFormView from konova.views.modal import AbstractModalFormView
from user.forms.modals.api_token import NewAPITokenModalForm from user.forms.modals.api_token import NewAPITokenModalForm
from user.models import User from user.models import User
@ -38,7 +38,7 @@ class APITokenView(View):
context = BaseContext(request, context).context context = BaseContext(request, context).context
return render(request, template, context) return render(request, template, context)
class NewAPITokenView(LoginRequiredMixin, BaseModalFormView): class NewAPITokenView(LoginRequiredMixin, AbstractModalFormView):
_MODEL_CLS = User _MODEL_CLS = User
_FORM_CLS = NewAPITokenModalForm _FORM_CLS = NewAPITokenModalForm
_MSG_SUCCESS = NEW_API_TOKEN_GENERATED _MSG_SUCCESS = NEW_API_TOKEN_GENERATED

View File

@ -11,14 +11,14 @@ from django.utils.translation import gettext_lazy as _
from konova.contexts import BaseContext from konova.contexts import BaseContext
from konova.utils.message_templates import TEAM_LEFT, TEAM_REMOVED, TEAM_EDITED, TEAM_ADDED from konova.utils.message_templates import TEAM_LEFT, TEAM_REMOVED, TEAM_EDITED, TEAM_ADDED
from konova.views.base import BaseModalFormView from konova.views.modal import AbstractModalFormView
from user.forms.modals.team import LeaveTeamModalForm, RemoveTeamModalForm, EditTeamModalForm, NewTeamModalForm from user.forms.modals.team import LeaveTeamModalForm, RemoveTeamModalForm, EditTeamModalForm, NewTeamModalForm
from user.forms.team import TeamDataForm from user.forms.team import TeamDataForm
from user.models import Team from user.models import Team
from user.views.users import UserBaseView from user.views.users import UserBaseView
class TeamDetailModalView(LoginRequiredMixin, BaseModalFormView): class TeamDetailModalView(LoginRequiredMixin, AbstractModalFormView):
_FORM_CLS = TeamDataForm _FORM_CLS = TeamDataForm
_MODEL_CLS = Team _MODEL_CLS = Team
@ -45,7 +45,7 @@ class TeamIndexView(LoginRequiredMixin, UserBaseView):
return render(request, self._TEMPLATE, context) return render(request, self._TEMPLATE, context)
class BaseTeamView(LoginRequiredMixin, BaseModalFormView): class BaseTeamView(LoginRequiredMixin, AbstractModalFormView):
_REDIRECT_URL = "user:team-index" _REDIRECT_URL = "user:team-index"
_MODEL_CLS = Team _MODEL_CLS = Team

View File

@ -2,7 +2,7 @@ from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
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, BaseModalFormView from konova.views.modal import AbstractBaseView, AbstractModalFormView
from user.forms.modals.user import UserContactForm from user.forms.modals.user import UserContactForm
from user.forms.user import UserNotificationForm from user.forms.user import UserNotificationForm
from user.models import User from user.models import User
@ -13,7 +13,7 @@ from django.utils.translation import gettext_lazy as _
from konova.contexts import BaseContext from konova.contexts import BaseContext
class UserBaseView(BaseView): class UserBaseView(AbstractBaseView):
def _user_has_shared_access(self, user, **kwargs): def _user_has_shared_access(self, user, **kwargs):
return True return True
@ -68,7 +68,7 @@ class NotificationsView(LoginRequiredMixin, UserBaseView):
return render(request, self._TEMPLATE, context) return render(request, self._TEMPLATE, context)
class ContactView(LoginRequiredMixin, BaseModalFormView): class ContactView(LoginRequiredMixin, AbstractModalFormView):
_FORM_CLS = UserContactForm _FORM_CLS = UserContactForm
_MODEL_CLS = User _MODEL_CLS = User