Compare commits
11 Commits
1.12
...
afbdf221c3
| Author | SHA1 | Date | |
|---|---|---|---|
| afbdf221c3 | |||
| be9f6f1b7e | |||
| 80e8925a63 | |||
| c597e1934b | |||
| a44d8658d4 | |||
| bb71c0fcc8 | |||
| 67acddf701 | |||
| 21bb988d86 | |||
| 1ceffccd40 | |||
| e5db7f6b13 | |||
| 442f3ceb37 |
@@ -54,7 +54,7 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase):
|
||||
post_data = {
|
||||
"identifier": test_id,
|
||||
"title": test_title,
|
||||
"geom": geom_json,
|
||||
"output": geom_json,
|
||||
"intervention": self.intervention.id,
|
||||
}
|
||||
pre_creation_intervention_log_count = self.intervention.log.count()
|
||||
@@ -94,7 +94,7 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase):
|
||||
post_data = {
|
||||
"identifier": test_id,
|
||||
"title": test_title,
|
||||
"geom": geom_json,
|
||||
"output": geom_json,
|
||||
}
|
||||
pre_creation_intervention_log_count = self.intervention.log.count()
|
||||
|
||||
@@ -150,7 +150,7 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase):
|
||||
"title": new_title,
|
||||
"intervention": self.intervention.id, # just keep the intervention as it is
|
||||
"comment": new_comment,
|
||||
"geom": geojson,
|
||||
"output": geojson,
|
||||
}
|
||||
self.client_user.post(url, post_data)
|
||||
self.compensation.refresh_from_db()
|
||||
|
||||
@@ -46,7 +46,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
|
||||
post_data = {
|
||||
"identifier": test_id,
|
||||
"title": test_title,
|
||||
"geom": geom_json,
|
||||
"output": geom_json,
|
||||
"surface": test_deductable_surface,
|
||||
"conservation_office": test_conservation_office.id
|
||||
}
|
||||
@@ -103,7 +103,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
|
||||
"identifier": new_identifier,
|
||||
"title": new_title,
|
||||
"comment": new_comment,
|
||||
"geom": self.create_geojson(new_geometry),
|
||||
"output": self.create_geojson(new_geometry),
|
||||
"surface": test_deductable_surface,
|
||||
"conservation_office": test_conservation_office.id
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@ from compensation.views.compensation.action import NewCompensationActionView, Ed
|
||||
RemoveCompensationActionView
|
||||
from compensation.views.compensation.state import NewCompensationStateView, EditCompensationStateView, \
|
||||
RemoveCompensationStateView
|
||||
from compensation.views.compensation.compensation import index_view, new_view, new_id_view, detail_view, edit_view, \
|
||||
remove_view
|
||||
from compensation.views.compensation.compensation import new_view, detail_view, edit_view, \
|
||||
remove_view, CompensationIndexView, CompensationIdentifierGeneratorView
|
||||
from compensation.views.compensation.log import CompensationLogView
|
||||
|
||||
urlpatterns = [
|
||||
# Main compensation
|
||||
path("", index_view, name="index"),
|
||||
path('new/id', new_id_view, name='new-id'),
|
||||
path("", CompensationIndexView.as_view(), name="index"),
|
||||
path('new/id', CompensationIdentifierGeneratorView.as_view(), name='new-id'),
|
||||
path('new/<intervention_id>', new_view, name='new'),
|
||||
path('new', new_view, name='new'),
|
||||
path('<id>', detail_view, name='detail'),
|
||||
|
||||
@@ -8,8 +8,8 @@ Created on: 24.08.21
|
||||
from django.urls import path
|
||||
|
||||
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, \
|
||||
detail_view
|
||||
from compensation.views.eco_account.eco_account import new_view, edit_view, remove_view, \
|
||||
detail_view, EcoAccountIndexView, EcoAccountIdentifierGeneratorView
|
||||
from compensation.views.eco_account.log import EcoAccountLogView
|
||||
from compensation.views.eco_account.record import EcoAccountRecordView
|
||||
from compensation.views.eco_account.report import report_view
|
||||
@@ -28,9 +28,9 @@ from compensation.views.eco_account.deduction import NewEcoAccountDeductionView,
|
||||
|
||||
app_name = "acc"
|
||||
urlpatterns = [
|
||||
path("", index_view, name="index"),
|
||||
path("", EcoAccountIndexView.as_view(), name="index"),
|
||||
path('new/', new_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>/log', EcoAccountLogView.as_view(), name='log'),
|
||||
path('<id>/record', EcoAccountRecordView.as_view(), name='record'),
|
||||
|
||||
@@ -7,8 +7,8 @@ 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.core.exceptions import ObjectDoesNotExist
|
||||
from django.db.models import Sum
|
||||
from django.http import HttpRequest, JsonResponse
|
||||
from django.shortcuts import get_object_or_404, render, redirect
|
||||
from django.urls import reverse
|
||||
@@ -27,38 +27,22 @@ 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, \
|
||||
RECORDED_BLOCKS_EDIT, CHECK_STATE_RESET, FORM_INVALID, PARAMS_INVALID, IDENTIFIER_REPLACED, \
|
||||
COMPENSATION_ADDED_TEMPLATE, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED
|
||||
COMPENSATION_ADDED_TEMPLATE, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
|
||||
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
|
||||
|
||||
|
||||
@login_required
|
||||
@any_group_check
|
||||
def index_view(request: HttpRequest):
|
||||
"""
|
||||
Renders the index view for compensation
|
||||
class CompensationIndexView(LoginRequiredMixin, BaseIndexView):
|
||||
_TAB_TITLE = _("Compensations - Overview")
|
||||
_INDEX_TABLE_CLS = CompensationTable
|
||||
|
||||
Args:
|
||||
request (HttpRequest): The incoming request
|
||||
|
||||
Returns:
|
||||
A rendered view
|
||||
"""
|
||||
template = "generic_index.html"
|
||||
compensations = Compensation.objects.filter(
|
||||
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)
|
||||
def _get_queryset(self):
|
||||
qs = Compensation.objects.filter(
|
||||
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"
|
||||
)
|
||||
return qs
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -103,11 +87,19 @@ def new_view(request: HttpRequest, intervention_id: str = None):
|
||||
)
|
||||
)
|
||||
messages.success(request, COMPENSATION_ADDED_TEMPLATE.format(comp.identifier))
|
||||
if geom_form.geometry_simplified:
|
||||
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",)
|
||||
@@ -123,23 +115,9 @@ def new_view(request: HttpRequest, intervention_id: str = None):
|
||||
return render(request, template, context)
|
||||
|
||||
|
||||
@login_required
|
||||
@default_group_required
|
||||
def new_id_view(request: HttpRequest):
|
||||
""" JSON endpoint
|
||||
|
||||
Provides fetching of free identifiers for e.g. AJAX calls
|
||||
|
||||
"""
|
||||
tmp = Compensation()
|
||||
identifier = tmp.generate_new_identifier()
|
||||
while Compensation.objects.filter(identifier=identifier).exists():
|
||||
identifier = tmp.generate_new_identifier()
|
||||
return JsonResponse(
|
||||
data={
|
||||
"gen_data": identifier
|
||||
}
|
||||
)
|
||||
class CompensationIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
|
||||
_MODEL_CLS = Compensation
|
||||
_REDIRECT_URL_NAME = "compensation:index"
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -179,11 +157,19 @@ def edit_view(request: HttpRequest, id: str):
|
||||
if intervention_is_checked:
|
||||
messages.info(request, CHECK_STATE_RESET)
|
||||
messages.success(request, _("Compensation {} edited").format(comp.identifier))
|
||||
if geom_form.geometry_simplified:
|
||||
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",)
|
||||
|
||||
@@ -7,7 +7,7 @@ Created on: 19.08.22
|
||||
"""
|
||||
from django.contrib import messages
|
||||
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.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
@@ -23,37 +23,21 @@ from konova.forms import SimpleGeomForm
|
||||
from konova.settings import ETS_GROUP, DEFAULT_GROUP, ZB_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, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED
|
||||
IDENTIFIER_REPLACED, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
|
||||
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
|
||||
|
||||
|
||||
@login_required
|
||||
@any_group_check
|
||||
def index_view(request: HttpRequest):
|
||||
"""
|
||||
Renders the index view for eco accounts
|
||||
class EcoAccountIndexView(LoginRequiredMixin, BaseIndexView):
|
||||
_INDEX_TABLE_CLS = EcoAccountTable
|
||||
_TAB_TITLE = _("Eco-account - Overview")
|
||||
|
||||
Args:
|
||||
request (HttpRequest): The incoming request
|
||||
|
||||
Returns:
|
||||
A rendered view
|
||||
"""
|
||||
template = "generic_index.html"
|
||||
eco_accounts = EcoAccount.objects.filter(
|
||||
deleted=None,
|
||||
).order_by(
|
||||
"-modified__timestamp"
|
||||
)
|
||||
table = EcoAccountTable(
|
||||
request=request,
|
||||
queryset=eco_accounts
|
||||
)
|
||||
context = {
|
||||
"table": table,
|
||||
TAB_TITLE_IDENTIFIER: _("Eco-account - Overview"),
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(request, template, context)
|
||||
def _get_queryset(self):
|
||||
qs = EcoAccount.objects.filter(
|
||||
deleted=None,
|
||||
).order_by(
|
||||
"-modified__timestamp"
|
||||
)
|
||||
return qs
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -84,11 +68,19 @@ def new_view(request: HttpRequest):
|
||||
)
|
||||
)
|
||||
messages.success(request, _("Eco-Account {} added").format(acc.identifier))
|
||||
if geom_form.geometry_simplified:
|
||||
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",)
|
||||
@@ -104,23 +96,9 @@ def new_view(request: HttpRequest):
|
||||
return render(request, template, context)
|
||||
|
||||
|
||||
@login_required
|
||||
@default_group_required
|
||||
def new_id_view(request: HttpRequest):
|
||||
""" 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
|
||||
}
|
||||
)
|
||||
class EcoAccountIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
|
||||
_MODEL_CLS = EcoAccount
|
||||
_REDIRECT_URL_NAME = "compensation:acc:index"
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -156,11 +134,19 @@ def edit_view(request: HttpRequest, id: str):
|
||||
# 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.geometry_simplified:
|
||||
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",)
|
||||
|
||||
@@ -46,7 +46,7 @@ class EmaWorkflowTestCase(BaseWorkflowTestCase):
|
||||
post_data = {
|
||||
"identifier": test_id,
|
||||
"title": test_title,
|
||||
"geom": geom_json,
|
||||
"output": geom_json,
|
||||
"conservation_office": test_conservation_office.id
|
||||
}
|
||||
self.client_user.post(new_url, post_data)
|
||||
@@ -99,7 +99,7 @@ class EmaWorkflowTestCase(BaseWorkflowTestCase):
|
||||
"identifier": new_identifier,
|
||||
"title": new_title,
|
||||
"comment": new_comment,
|
||||
"geom": self.create_geojson(new_geometry),
|
||||
"output": self.create_geojson(new_geometry),
|
||||
"conservation_office": test_conservation_office.id
|
||||
}
|
||||
self.client_user.post(url, post_data)
|
||||
|
||||
@@ -48,7 +48,7 @@ class NewEmaFormTestCase(BaseTestCase):
|
||||
)
|
||||
geom_form_data = json.loads(geom_form_data)
|
||||
geom_form_data = {
|
||||
"geom": json.dumps(geom_form_data)
|
||||
"output": json.dumps(geom_form_data)
|
||||
}
|
||||
|
||||
geom_form = SimpleGeomForm(geom_form_data)
|
||||
@@ -116,7 +116,7 @@ class EditEmaFormTestCase(BaseTestCase):
|
||||
)
|
||||
geom_form_data = json.loads(geom_form_data)
|
||||
geom_form_data = {
|
||||
"geom": json.dumps(geom_form_data)
|
||||
"output": json.dumps(geom_form_data)
|
||||
}
|
||||
|
||||
geom_form = SimpleGeomForm(geom_form_data)
|
||||
|
||||
@@ -10,7 +10,8 @@ from django.urls import path
|
||||
from ema.views.action import NewEmaActionView, EditEmaActionView, RemoveEmaActionView
|
||||
from ema.views.deadline import NewEmaDeadlineView, EditEmaDeadlineView, RemoveEmaDeadlineView
|
||||
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 new_view, detail_view, edit_view, remove_view, EmaIndexView, \
|
||||
EmaIdentifierGeneratorView
|
||||
from ema.views.log import EmaLogView
|
||||
from ema.views.record import EmaRecordView
|
||||
from ema.views.report import report_view
|
||||
@@ -20,9 +21,9 @@ from ema.views.state import NewEmaStateView, EditEmaStateView, RemoveEmaStateVie
|
||||
|
||||
app_name = "ema"
|
||||
urlpatterns = [
|
||||
path("", index_view, name="index"),
|
||||
path("", EmaIndexView.as_view(), name="index"),
|
||||
path("new/", new_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>/log', EmaLogView.as_view(), name='log'),
|
||||
path('<id>/edit', edit_view, name='edit'),
|
||||
|
||||
@@ -7,7 +7,7 @@ Created on: 19.08.22
|
||||
"""
|
||||
from django.contrib import messages
|
||||
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.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
@@ -24,36 +24,21 @@ 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
|
||||
DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE, MISSING_GROUP_PERMISSION
|
||||
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
|
||||
|
||||
|
||||
@login_required
|
||||
def index_view(request: HttpRequest):
|
||||
""" Renders the index view for EMAs
|
||||
class EmaIndexView(LoginRequiredMixin, BaseIndexView):
|
||||
_TAB_TITLE = _("EMAs - Overview")
|
||||
_INDEX_TABLE_CLS = EmaTable
|
||||
|
||||
Args:
|
||||
request (HttpRequest): The incoming request
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
template = "generic_index.html"
|
||||
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)
|
||||
def _get_queryset(self):
|
||||
qs = Ema.objects.filter(
|
||||
deleted=None,
|
||||
).order_by(
|
||||
"-modified__timestamp"
|
||||
)
|
||||
return qs
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -84,11 +69,17 @@ def new_view(request: HttpRequest):
|
||||
)
|
||||
)
|
||||
messages.success(request, _("EMA {} added").format(ema.identifier))
|
||||
if geom_form.geometry_simplified:
|
||||
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:
|
||||
@@ -105,23 +96,12 @@ def new_view(request: HttpRequest):
|
||||
return render(request, template, context)
|
||||
|
||||
|
||||
@login_required
|
||||
@conservation_office_group_required
|
||||
def new_id_view(request: HttpRequest):
|
||||
""" JSON endpoint
|
||||
class EmaIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
|
||||
_MODEL_CLS = Ema
|
||||
_REDIRECT_URL_NAME = "ema:index"
|
||||
|
||||
Provides fetching of free identifiers for e.g. AJAX calls
|
||||
|
||||
"""
|
||||
tmp = Ema()
|
||||
identifier = tmp.generate_new_identifier()
|
||||
while Ema.objects.filter(identifier=identifier).exists():
|
||||
identifier = tmp.generate_new_identifier()
|
||||
return JsonResponse(
|
||||
data={
|
||||
"gen_data": identifier
|
||||
}
|
||||
)
|
||||
def _user_has_permission(self, user):
|
||||
return user.is_ets_user()
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -215,11 +195,19 @@ def edit_view(request: HttpRequest, id: str):
|
||||
# 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.geometry_simplified:
|
||||
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",)
|
||||
|
||||
@@ -60,7 +60,7 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
|
||||
post_data = {
|
||||
"identifier": test_id,
|
||||
"title": test_title,
|
||||
"geom": geom_json,
|
||||
"output": geom_json,
|
||||
}
|
||||
response = self.client_user.post(
|
||||
new_url,
|
||||
|
||||
@@ -62,7 +62,7 @@ class NewInterventionFormTestCase(BaseTestCase):
|
||||
)
|
||||
geom_form_data = json.loads(geom_form_data)
|
||||
geom_form_data = {
|
||||
"geom": json.dumps(geom_form_data)
|
||||
"output": json.dumps(geom_form_data)
|
||||
}
|
||||
geom_form = SimpleGeomForm(geom_form_data)
|
||||
|
||||
@@ -104,7 +104,7 @@ class EditInterventionFormTestCase(NewInterventionFormTestCase):
|
||||
)
|
||||
geom_form_data = json.loads(geom_form_data)
|
||||
geom_form_data = {
|
||||
"geom": json.dumps(geom_form_data)
|
||||
"output": json.dumps(geom_form_data)
|
||||
}
|
||||
|
||||
geom_form = SimpleGeomForm(geom_form_data)
|
||||
|
||||
@@ -14,7 +14,8 @@ from intervention.views.deduction import NewInterventionDeductionView, EditInter
|
||||
RemoveInterventionDeductionView
|
||||
from intervention.views.document import NewInterventionDocumentView, GetInterventionDocumentView, \
|
||||
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 new_view, detail_view, edit_view, remove_view, \
|
||||
InterventionIndexView, InterventionIdentifierGeneratorView
|
||||
from intervention.views.log import InterventionLogView
|
||||
from intervention.views.record import InterventionRecordView
|
||||
from intervention.views.report import report_view
|
||||
@@ -25,9 +26,9 @@ from intervention.views.share import InterventionShareFormView, InterventionShar
|
||||
|
||||
app_name = "intervention"
|
||||
urlpatterns = [
|
||||
path("", index_view, name="index"),
|
||||
path("", InterventionIndexView.as_view(), name="index"),
|
||||
path('new/', new_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>/log', InterventionLogView.as_view(), name='log'),
|
||||
path('<id>/edit', edit_view, name='edit'),
|
||||
|
||||
@@ -7,6 +7,7 @@ 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.http import JsonResponse, HttpRequest
|
||||
from django.shortcuts import get_object_or_404, render, redirect
|
||||
from django.urls import reverse
|
||||
@@ -23,41 +24,24 @@ 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 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, IDENTIFIER_REPLACED, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, \
|
||||
GEOMETRIES_IGNORED_TEMPLATE
|
||||
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
|
||||
|
||||
|
||||
@login_required
|
||||
@any_group_check
|
||||
def index_view(request: HttpRequest):
|
||||
"""
|
||||
Renders the index view for Interventions
|
||||
class InterventionIndexView(LoginRequiredMixin, BaseIndexView):
|
||||
_INDEX_TABLE_CLS = InterventionTable
|
||||
_TAB_TITLE = _("Interventions - Overview")
|
||||
|
||||
Args:
|
||||
request (HttpRequest): The incoming request
|
||||
|
||||
Returns:
|
||||
A rendered view
|
||||
"""
|
||||
template = "generic_index.html"
|
||||
|
||||
# Filtering by user access is performed in table filter inside InterventionTableFilter class
|
||||
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)
|
||||
def _get_queryset(self):
|
||||
qs = Intervention.objects.filter(
|
||||
deleted=None,
|
||||
).select_related(
|
||||
"legal"
|
||||
).order_by(
|
||||
"-modified__timestamp"
|
||||
)
|
||||
return qs
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -88,11 +72,19 @@ def new_view(request: HttpRequest):
|
||||
)
|
||||
)
|
||||
messages.success(request, _("Intervention {} added").format(intervention.identifier))
|
||||
if geom_form.geometry_simplified:
|
||||
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",)
|
||||
@@ -108,23 +100,9 @@ def new_view(request: HttpRequest):
|
||||
return render(request, template, context)
|
||||
|
||||
|
||||
@login_required
|
||||
@default_group_required
|
||||
def new_id_view(request: HttpRequest):
|
||||
""" JSON endpoint
|
||||
|
||||
Provides fetching of free identifiers for e.g. AJAX calls
|
||||
|
||||
"""
|
||||
tmp_intervention = Intervention()
|
||||
identifier = tmp_intervention.generate_new_identifier()
|
||||
while Intervention.objects.filter(identifier=identifier).exists():
|
||||
identifier = tmp_intervention.generate_new_identifier()
|
||||
return JsonResponse(
|
||||
data={
|
||||
"gen_data": identifier
|
||||
}
|
||||
)
|
||||
class InterventionIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
|
||||
_MODEL_CLS = Intervention
|
||||
_REDIRECT_URL_NAME = "intervention:index"
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -236,11 +214,19 @@ def edit_view(request: HttpRequest, id: str):
|
||||
messages.success(request, _("Intervention {} edited").format(intervention.identifier))
|
||||
if intervention_is_checked:
|
||||
messages.info(request, CHECK_STATE_RESET)
|
||||
if geom_form.geometry_simplified:
|
||||
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",)
|
||||
|
||||
@@ -25,8 +25,8 @@ class SimpleGeomForm(BaseForm):
|
||||
""" A geometry form for rendering geometry read-only using a widget
|
||||
|
||||
"""
|
||||
read_only = True
|
||||
geometry_simplified = False
|
||||
read_only: bool = True
|
||||
_geometry_simplified: bool = False
|
||||
output = JSONField(
|
||||
label=_("Geometry"),
|
||||
help_text=_(""),
|
||||
@@ -34,6 +34,7 @@ class SimpleGeomForm(BaseForm):
|
||||
required=False,
|
||||
disabled=False,
|
||||
)
|
||||
_num_geometries_ignored: int = 0
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.read_only = kwargs.pop("read_only", True)
|
||||
@@ -48,6 +49,7 @@ class SimpleGeomForm(BaseForm):
|
||||
raise AttributeError
|
||||
|
||||
geojson = self.instance.geometry.as_feature_collection(srid=DEFAULT_SRID_RLP)
|
||||
self._set_geojson_properties(geojson, title=self.instance.identifier or None)
|
||||
geom = json.dumps(geojson)
|
||||
except AttributeError:
|
||||
# If no geometry exists for this form, we simply set the value to None and zoom to the maximum level
|
||||
@@ -61,7 +63,7 @@ class SimpleGeomForm(BaseForm):
|
||||
is_valid = True
|
||||
|
||||
# Get geojson from form
|
||||
geom = self.data["output"]
|
||||
geom = self.data.get("output", None)
|
||||
if geom is None or len(geom) == 0:
|
||||
# empty geometry is a valid geometry
|
||||
self.cleaned_data["output"] = MultiPolygon(srid=DEFAULT_SRID_RLP).ewkt
|
||||
@@ -100,7 +102,13 @@ class SimpleGeomForm(BaseForm):
|
||||
is_valid &= False
|
||||
return is_valid
|
||||
|
||||
is_valid &= self.__is_area_valid(g)
|
||||
is_area_valid = self.__is_area_valid(g)
|
||||
if not is_area_valid:
|
||||
# Geometries with an invalid size will not be saved to the db
|
||||
# We assume these are malicious snippets which are not supposed to be in the geometry in the first place
|
||||
self._num_geometries_ignored += 1
|
||||
continue
|
||||
|
||||
g = Polygon.from_ewkt(g.ewkt)
|
||||
is_valid &= g.valid
|
||||
if not g.valid:
|
||||
@@ -147,15 +155,6 @@ class SimpleGeomForm(BaseForm):
|
||||
|
||||
"""
|
||||
is_area_valid = geom.area > 1 # > 1m² (SRID:25832)
|
||||
|
||||
if not is_area_valid:
|
||||
self.add_error(
|
||||
"output",
|
||||
_("Geometry must be greater than 1m². Currently is {}m²").format(
|
||||
float(geom.area)
|
||||
)
|
||||
)
|
||||
|
||||
return is_area_valid
|
||||
|
||||
def __simplify_geometry(self, geom, max_vert: int):
|
||||
@@ -208,13 +207,29 @@ class SimpleGeomForm(BaseForm):
|
||||
if not is_vertices_num_valid:
|
||||
geometry.geom = self.__simplify_geometry(geometry.geom, max_vert=GEOM_MAX_VERTICES)
|
||||
geometry.save()
|
||||
self.geometry_simplified = True
|
||||
self._geometry_simplified = True
|
||||
|
||||
# Start parcel update and geometry conflict checking procedure in a background process
|
||||
celery_update_parcels.delay(geometry.id)
|
||||
celery_check_for_geometry_conflicts.delay(geometry.id)
|
||||
return geometry
|
||||
|
||||
def get_num_geometries_ignored(self):
|
||||
""" Returns the number of geometries which had to be ignored for various reasons
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
return self._num_geometries_ignored
|
||||
|
||||
def has_geometry_simplified(self):
|
||||
""" Returns whether the geometry has been simplified or not.
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
return self._geometry_simplified
|
||||
|
||||
def __flatten_geom_to_2D(self, geom):
|
||||
"""
|
||||
Enforces a given OGRGeometry from higher dimensions into 2D
|
||||
@@ -225,11 +240,12 @@ class SimpleGeomForm(BaseForm):
|
||||
geom = gdal.OGRGeometry(g_wkt)
|
||||
return geom
|
||||
|
||||
def _set_properties(self, geojson: dict, title: str):
|
||||
def _set_geojson_properties(self, geojson: dict, title: str = None):
|
||||
""" Toggles the editable property of the geojson for proper handling in map client
|
||||
|
||||
Args:
|
||||
geojson (dict): The GeoJson
|
||||
title (str): An alternative title for the geometry
|
||||
|
||||
Returns:
|
||||
geojson (dict): The altered GeoJson
|
||||
|
||||
@@ -124,6 +124,7 @@ class GeometryTestCase(BaseTestCase):
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": json.loads(p.json),
|
||||
"properties": {}
|
||||
}
|
||||
for p in polygons
|
||||
]
|
||||
|
||||
@@ -5,6 +5,9 @@ Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 17.09.21
|
||||
|
||||
"""
|
||||
from django.contrib import messages
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.http import HttpRequest
|
||||
|
||||
|
||||
def format_german_float(num) -> str:
|
||||
@@ -19,3 +22,19 @@ def format_german_float(num) -> str:
|
||||
num (str): The number as german Gleitkommazahl
|
||||
"""
|
||||
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
|
||||
|
||||
@@ -83,6 +83,7 @@ EDITED_GENERAL_DATA = _("Edited general data")
|
||||
# Geometry
|
||||
GEOMETRY_CONFLICT_WITH_TEMPLATE = _("Geometry conflict detected with {}")
|
||||
GEOMETRY_SIMPLIFIED = _("The geometry contained more than {} vertices. It had to be simplified to match the allowed limit of {} vertices.").format(GEOM_MAX_VERTICES, GEOM_MAX_VERTICES)
|
||||
GEOMETRIES_IGNORED_TEMPLATE = _("The geometry contained {} parts which have been detected as invalid (e.g. too small to be valid). These parts have been removed. Please check the stored geometry.")
|
||||
|
||||
# INTERVENTION
|
||||
INTERVENTION_HAS_REVOCATIONS_TEMPLATE = _("This intervention has {} revocations")
|
||||
|
||||
98
konova/views/base.py
Normal file
98
konova/views/base.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""
|
||||
Author: Michel Peltriaux
|
||||
Created on: 15.10.25
|
||||
|
||||
"""
|
||||
from abc import abstractmethod
|
||||
|
||||
from django.contrib import messages
|
||||
from django.http import HttpRequest, JsonResponse
|
||||
from django.shortcuts import render, redirect
|
||||
from django.urls import reverse
|
||||
from django.views import View
|
||||
|
||||
from konova.contexts import BaseContext
|
||||
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
|
||||
|
||||
|
||||
class BaseView(View):
|
||||
_TEMPLATE: str = "CHANGE_ME"
|
||||
_TAB_TITLE: str = "CHANGE_ME"
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class BaseModalFormView(BaseView):
|
||||
_TEMPLATE = "modal/modal_form.html"
|
||||
_TAB_TITLE = None
|
||||
|
||||
|
||||
class BaseIndexView(BaseView):
|
||||
""" Base class for index views
|
||||
|
||||
"""
|
||||
_TEMPLATE = "generic_index.html"
|
||||
_INDEX_TABLE_CLS = None
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
request = check_user_is_in_any_group(request)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get(self, request: HttpRequest):
|
||||
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):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class BaseIdentifierGeneratorView(View):
|
||||
_MODEL_CLS = None
|
||||
_REDIRECT_URL_NAME: str = "home"
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not self._user_has_permission(request.user):
|
||||
messages.info(request, MISSING_GROUP_PERMISSION)
|
||||
return redirect(reverse(self._REDIRECT_URL_NAME))
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
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):
|
||||
""" Should be overwritten in inheriting classes!
|
||||
|
||||
Args:
|
||||
user ():
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
return user.is_default_user()
|
||||
Binary file not shown.
@@ -45,7 +45,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-05-12 14:22+0200\n"
|
||||
"POT-Creation-Date: 2025-10-15 09:11+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -1298,13 +1298,13 @@ msgid "Compensation {} edited"
|
||||
msgstr "Kompensation {} bearbeitet"
|
||||
|
||||
#: compensation/views/compensation/compensation.py:196
|
||||
#: compensation/views/eco_account/eco_account.py:173 ema/views/ema.py:232
|
||||
#: compensation/views/eco_account/eco_account.py:173 ema/views/ema.py:238
|
||||
#: intervention/views/intervention.py:253
|
||||
msgid "Edit {}"
|
||||
msgstr "Bearbeite {}"
|
||||
|
||||
#: compensation/views/compensation/report.py:35
|
||||
#: compensation/views/eco_account/report.py:35 ema/views/report.py:35
|
||||
#: compensation/views/eco_account/report.py:36 ema/views/report.py:35
|
||||
#: intervention/views/report.py:35
|
||||
msgid "Report {}"
|
||||
msgstr "Bericht {}"
|
||||
@@ -1325,7 +1325,7 @@ msgstr "Ökokonto {} bearbeitet"
|
||||
msgid "Eco-account removed"
|
||||
msgstr "Ökokonto entfernt"
|
||||
|
||||
#: ema/forms.py:42 ema/tests/unit/test_forms.py:27 ema/views/ema.py:102
|
||||
#: ema/forms.py:42 ema/tests/unit/test_forms.py:27 ema/views/ema.py:108
|
||||
msgid "New EMA"
|
||||
msgstr "Neue EMA hinzufügen"
|
||||
|
||||
@@ -1361,11 +1361,11 @@ msgstr "EMAs - Übersicht"
|
||||
msgid "EMA {} added"
|
||||
msgstr "EMA {} hinzugefügt"
|
||||
|
||||
#: ema/views/ema.py:217
|
||||
#: ema/views/ema.py:223
|
||||
msgid "EMA {} edited"
|
||||
msgstr "EMA {} bearbeitet"
|
||||
|
||||
#: ema/views/ema.py:256
|
||||
#: ema/views/ema.py:262
|
||||
msgid "EMA removed"
|
||||
msgstr "EMA entfernt"
|
||||
|
||||
@@ -1815,10 +1815,6 @@ msgid "Only surfaces allowed. Points or lines must be buffered."
|
||||
msgstr ""
|
||||
"Nur Flächen erlaubt. Punkte oder Linien müssen zu Flächen gepuffert werden."
|
||||
|
||||
#: konova/forms/geometry_form.py:153
|
||||
msgid "Geometry must be greater than 1m². Currently is {}m²"
|
||||
msgstr "Geometrie muss größer als 1m² sein. Aktueller Flächeninhalt: {}m²"
|
||||
|
||||
#: konova/forms/modals/document_form.py:37
|
||||
msgid "When has this file been created? Important for photos."
|
||||
msgstr "Wann wurde diese Datei erstellt oder das Foto aufgenommen?"
|
||||
@@ -2266,24 +2262,33 @@ msgstr ""
|
||||
"Die Geometrie enthielt mehr als {} Eckpunkte. Sie musste vereinfacht werden "
|
||||
"um die Obergrenze von {} erlaubten Eckpunkten einzuhalten."
|
||||
|
||||
#: konova/utils/message_templates.py:88
|
||||
#: konova/utils/message_templates.py:86
|
||||
msgid ""
|
||||
"The geometry contained {} parts which have been detected as invalid (e.g. "
|
||||
"too small to be valid). These parts have been removed. Please check the "
|
||||
"stored geometry."
|
||||
msgstr ""
|
||||
"Die Geometrie enthielt {} invalide Bestandteile (z.B. unaussagekräftige Kleinstflächen)."
|
||||
"Diese Bestandteile wurden automatisch entfernt. Bitte überprüfen Sie die angepasste Geometrie."
|
||||
|
||||
#: konova/utils/message_templates.py:89
|
||||
msgid "This intervention has {} revocations"
|
||||
msgstr "Dem Eingriff liegen {} Widersprüche vor"
|
||||
|
||||
#: konova/utils/message_templates.py:91
|
||||
#: konova/utils/message_templates.py:92
|
||||
msgid "Checked on {} by {}"
|
||||
msgstr "Am {} von {} geprüft worden"
|
||||
|
||||
#: konova/utils/message_templates.py:92
|
||||
#: konova/utils/message_templates.py:93
|
||||
msgid "Data has changed since last check on {} by {}"
|
||||
msgstr ""
|
||||
"Daten wurden nach der letzten Prüfung geändert. Letzte Prüfung am {} durch {}"
|
||||
|
||||
#: konova/utils/message_templates.py:93
|
||||
#: konova/utils/message_templates.py:94
|
||||
msgid "Current data not checked yet"
|
||||
msgstr "Momentane Daten noch nicht geprüft"
|
||||
|
||||
#: konova/utils/message_templates.py:96
|
||||
#: konova/utils/message_templates.py:97
|
||||
msgid "New token generated. Administrators need to validate."
|
||||
msgstr "Neuer Token generiert. Administratoren sind informiert."
|
||||
|
||||
@@ -2313,14 +2318,6 @@ msgstr "Home"
|
||||
msgid "Log"
|
||||
msgstr "Log"
|
||||
|
||||
#: konova/views/map_proxy.py:84
|
||||
msgid ""
|
||||
"The external service is currently unavailable.<br>Please try again in a few "
|
||||
"moments..."
|
||||
msgstr ""
|
||||
"Der externe Dienst ist zur Zeit nicht erreichbar.<br>Versuchen Sie es in ein "
|
||||
"paar Sekunden nochmal."
|
||||
|
||||
#: konova/views/record.py:30
|
||||
msgid "{} unrecorded"
|
||||
msgstr "{} entzeichnet"
|
||||
@@ -2377,17 +2374,19 @@ msgstr "Alle"
|
||||
msgid "News"
|
||||
msgstr "Neuigkeiten"
|
||||
|
||||
#: templates/400.html:7
|
||||
#: templates/400.html:12
|
||||
msgid "Request was invalid"
|
||||
msgstr "Anfrage fehlerhaft"
|
||||
|
||||
#: templates/400.html:10
|
||||
#: templates/400.html:17
|
||||
msgid "There seems to be a problem with the link you opened."
|
||||
msgstr "Es scheint ein Problem mit dem Link zu geben, den Sie geöffnet haben."
|
||||
|
||||
#: templates/400.html:11
|
||||
#: templates/400.html:18
|
||||
msgid "Make sure the URL is valid (no whitespaces, properly copied, ...)."
|
||||
msgstr "Stellen Sie sicher, dass die URL gültig ist (keine Leerzeichen, fehlerfrei kopiert, ...)."
|
||||
msgstr ""
|
||||
"Stellen Sie sicher, dass die URL gültig ist (keine Leerzeichen, fehlerfrei "
|
||||
"kopiert, ...)."
|
||||
|
||||
#: templates/404.html:7
|
||||
msgid "Not found"
|
||||
@@ -2401,11 +2400,11 @@ msgstr "Die angeforderten Daten existieren nicht."
|
||||
msgid "Make sure the URL is valid (no whitespaces, ...)."
|
||||
msgstr "Stellen Sie sicher, dass die URL gültig ist (keine Leerzeichen, ...)."
|
||||
|
||||
#: templates/500.html:7
|
||||
#: templates/500.html:12
|
||||
msgid "Server Error"
|
||||
msgstr ""
|
||||
|
||||
#: templates/500.html:10
|
||||
#: templates/500.html:17
|
||||
msgid "Something happened. Admins have been informed. We are working on it!"
|
||||
msgstr ""
|
||||
"Irgendetwas ist passiert. Die Administratoren wurden informiert. Wir "
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
{% if user.is_staff or user.is_superuser %}
|
||||
<a class="dropdown-item" target="_blank" href="{% url 'admin:index' %}">{% fa5_icon 'tools' %} {% trans 'Admin' %}</a>
|
||||
{% 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>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -38,7 +38,7 @@ class UserNotificationForm(BaseForm):
|
||||
self.form_title = _("Edit notifications")
|
||||
self.form_caption = _("")
|
||||
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
|
||||
notifications = UserNotification.objects.filter(
|
||||
|
||||
@@ -26,7 +26,7 @@ class UserViewTestCase(BaseViewTestCase):
|
||||
self.team.users.add(self.superuser)
|
||||
self.team.admins.add(self.superuser)
|
||||
# Prepare urls
|
||||
self.index_url = reverse("user:index", args=())
|
||||
self.index_url = reverse("user:detail", args=())
|
||||
self.notification_url = reverse("user:notifications", args=())
|
||||
self.api_token_url = reverse("user:api-token", args=())
|
||||
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_caption, "")
|
||||
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):
|
||||
selected_notification = UserNotification.objects.first()
|
||||
|
||||
10
user/urls.py
10
user/urls.py
@@ -15,15 +15,15 @@ from user.views.views import *
|
||||
|
||||
app_name = "user"
|
||||
urlpatterns = [
|
||||
path("", index_view, name="index"),
|
||||
path("", UserDetailView.as_view(), name="detail"),
|
||||
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/new", new_api_token_view, name="api-token-new"),
|
||||
path("contact/<id>", contact_view, name="contact"),
|
||||
path("team/", index_team_view, name="team-index"),
|
||||
path("contact/<id>", ContactView.as_view(), name="contact"),
|
||||
path("team/", TeamIndexView.as_view(), name="team-index"),
|
||||
path("team/new", new_team_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>/remove", remove_team_view, name="team-remove"),
|
||||
path("team/<id>/leave", leave_team_view, name="team-leave"),
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.urls import reverse
|
||||
|
||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
||||
from konova.views.base import BaseView, BaseModalFormView
|
||||
from user.forms.modals.team import NewTeamModalForm, EditTeamModalForm, RemoveTeamModalForm, LeaveTeamModalForm
|
||||
from user.forms.modals.user import UserContactForm
|
||||
from user.forms.team import TeamDataForm
|
||||
@@ -13,129 +15,108 @@ from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from konova.contexts import BaseContext
|
||||
from konova.decorators import any_group_check, login_required_modal
|
||||
from konova.decorators import login_required_modal
|
||||
|
||||
|
||||
@login_required
|
||||
@any_group_check
|
||||
def index_view(request: HttpRequest):
|
||||
""" Renders the user's data index view
|
||||
class UserDetailView(LoginRequiredMixin, BaseView):
|
||||
_TAB_TITLE = _("User settings")
|
||||
_TEMPLATE = "user/index.html"
|
||||
|
||||
Args:
|
||||
request ():
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
template = "user/index.html"
|
||||
context = {
|
||||
"user": request.user,
|
||||
TAB_TITLE_IDENTIFIER: _("User settings"),
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(request, template, context)
|
||||
def get(self, request: HttpRequest):
|
||||
context = {
|
||||
"user": request.user,
|
||||
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(request, self._TEMPLATE, context)
|
||||
|
||||
|
||||
@login_required
|
||||
@any_group_check
|
||||
def notifications_view(request: HttpRequest):
|
||||
""" Renders the notifications settings view
|
||||
class NotificationsView(LoginRequiredMixin, BaseView):
|
||||
_TEMPLATE = "user/notifications.html"
|
||||
_TAB_TITLE = _("User notifications")
|
||||
|
||||
Args:
|
||||
request ():
|
||||
def get(self, request: HttpRequest):
|
||||
user = request.user
|
||||
form = UserNotificationForm(user=user, data=None)
|
||||
context = {
|
||||
"user": user,
|
||||
"form": form,
|
||||
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(request, self._TEMPLATE, context)
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
template = "user/notifications.html"
|
||||
user = request.user
|
||||
|
||||
form = UserNotificationForm(user=user, data=request.POST or None)
|
||||
if request.method == "POST":
|
||||
def post(self, request: HttpRequest):
|
||||
user = request.user
|
||||
form = UserNotificationForm(user=user, data=request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(
|
||||
request,
|
||||
_("Notifications edited")
|
||||
)
|
||||
return redirect("user:index")
|
||||
elif request.method == "GET":
|
||||
# Implicit
|
||||
pass
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
context = {
|
||||
"user": user,
|
||||
"form": form,
|
||||
TAB_TITLE_IDENTIFIER: _("User notifications"),
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(request, template, context)
|
||||
return redirect("user:detail")
|
||||
context = {
|
||||
"user": user,
|
||||
"form": form,
|
||||
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(request, self._TEMPLATE, context)
|
||||
|
||||
|
||||
@login_required_modal
|
||||
@login_required
|
||||
def contact_view(request: HttpRequest, id: str):
|
||||
""" Renders contact modal view of a users contact data
|
||||
class ContactView(LoginRequiredMixin, BaseModalFormView):
|
||||
def get(self, request: HttpRequest, id: str):
|
||||
""" Renders contact modal view of a users contact data
|
||||
|
||||
Args:
|
||||
request (HttpRequest): The incoming request
|
||||
id (str): The user's id
|
||||
Args:
|
||||
request (HttpRequest): The incoming request
|
||||
id (str): The user's id
|
||||
|
||||
Returns:
|
||||
Returns:
|
||||
|
||||
"""
|
||||
user = get_object_or_404(User, id=id)
|
||||
form = UserContactForm(request.POST or None, instance=user, request=request)
|
||||
template = "modal/modal_form.html"
|
||||
context = {
|
||||
"form": form,
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(
|
||||
request,
|
||||
template,
|
||||
context
|
||||
)
|
||||
"""
|
||||
user = get_object_or_404(User, id=id)
|
||||
form = UserContactForm(request.POST or None, instance=user, request=request)
|
||||
context = {
|
||||
"form": form,
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(request, self._TEMPLATE, context)
|
||||
|
||||
|
||||
@login_required_modal
|
||||
@login_required
|
||||
def data_team_view(request: HttpRequest, id: str):
|
||||
""" Renders team data
|
||||
class TeamDetailModalView(LoginRequiredMixin, BaseModalFormView):
|
||||
def get(self, request: HttpRequest, id: str):
|
||||
""" Renders team data
|
||||
|
||||
Args:
|
||||
request (HttpRequest): The incoming request
|
||||
id (str): The team's id
|
||||
Args:
|
||||
request (HttpRequest): The incoming request
|
||||
id (str): The team's id
|
||||
|
||||
Returns:
|
||||
Returns:
|
||||
|
||||
"""
|
||||
team = get_object_or_404(Team, id=id)
|
||||
form = TeamDataForm(request.POST or None, instance=team, request=request)
|
||||
template = "modal/modal_form.html"
|
||||
context = {
|
||||
"form": form,
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(
|
||||
request,
|
||||
template,
|
||||
context
|
||||
)
|
||||
"""
|
||||
team = get_object_or_404(Team, id=id)
|
||||
form = TeamDataForm(request.POST or None, instance=team, request=request)
|
||||
context = {
|
||||
"form": form,
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(request, self._TEMPLATE, context)
|
||||
|
||||
|
||||
@login_required
|
||||
def index_team_view(request: HttpRequest):
|
||||
template = "user/team/index.html"
|
||||
user = request.user
|
||||
context = {
|
||||
"teams": user.shared_teams,
|
||||
"tab_title": _("Teams"),
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(request, template, context)
|
||||
class TeamIndexView(LoginRequiredMixin, BaseView):
|
||||
_TEMPLATE = "user/team/index.html"
|
||||
_TAB_TITLE = _("Teams")
|
||||
|
||||
def get(self, request: HttpRequest):
|
||||
user = request.user
|
||||
context = {
|
||||
"teams": user.shared_teams,
|
||||
"tab_title": self._TAB_TITLE,
|
||||
}
|
||||
context = BaseContext(request, context).context
|
||||
return render(request, self._TEMPLATE, context)
|
||||
|
||||
|
||||
@login_required_modal
|
||||
|
||||
Reference in New Issue
Block a user