Compare commits

..

No commits in common. "a2d5c4ddaa145cf017e1fa0ce7e84751bf2d8bdb" and "2fdf6606b33d2d6c8d038329e76b9bc3669f819b" have entirely different histories.

60 changed files with 397 additions and 1699 deletions

View File

@ -8,45 +8,20 @@ Created on: 29.07.21
import django_filters
from django.utils.translation import gettext_lazy as _
from django import forms
from django.db.models import QuerySet, Q
from django.db.models import QuerySet
from konova.filters.mixins import ConservationOfficeTableFilterMixin
from konova.filters.table_filters import QueryTableFilter, CheckboxTableFilter, SelectionTableFilter, AbstractTableFilter
from intervention.filters import InterventionTableFilter
class SelectionCompensationTableFilter(SelectionTableFilter):
""" Specialization of regular SelectionTableFilter for compensation model
class CompensationTableFilter(InterventionTableFilter):
""" TableFilter for compensations
"""
def filter_reg_office(self, queryset, name, value):
return queryset.filter(
intervention__responsible__registration_office=value
)
def filter_cons_office(self, queryset, name, value):
return queryset.filter(
intervention__responsible__conservation_office=value
)
class QueryCompensationTableFilter(QueryTableFilter):
""" Specialization of regular QueryTableFilter for compensation model
"""
def filter_file_number(self, queryset, name, value) -> QuerySet:
queryset = queryset.filter(
Q(intervention__responsible__registration_file_number__icontains=value) |
Q(intervention__responsible__conservation_file_number__icontains=value)
)
return queryset
class CheckboxCompensationTableFilter(CheckboxTableFilter):
""" Specialization of regular CheckboxTableFilter for compensation model
Based widely on InterventionTableFilter.
Just some minor changes for Compensation model.
"""
def filter_show_all(self, queryset, name, value) -> QuerySet:
def _filter_show_all(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_all' setting
Args:
@ -64,7 +39,7 @@ class CheckboxCompensationTableFilter(CheckboxTableFilter):
else:
return queryset
def filter_show_recorded(self, queryset, name, value) -> QuerySet:
def _filter_show_recorded(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_recorded' setting
Args:
@ -83,51 +58,21 @@ class CheckboxCompensationTableFilter(CheckboxTableFilter):
return queryset
class CompensationTableFilter(AbstractTableFilter):
""" TableFilter for compensations
class EcoAccountTableFilter(InterventionTableFilter):
""" TableFilter for eco accounts
Based widely on InterventionTableFilter.
Just some minor changes for Compensation model.
Just some minor changes for EcoAccount model.
"""
def __init__(self, user=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.user = user
qs = kwargs.get("queryset", None)
request_data = kwargs.get("data", None)
# Overwrite all filters for special needs of compensations
self.selection_filter = SelectionCompensationTableFilter(
data=request_data,
queryset=qs,
)
self.query_filter = QueryCompensationTableFilter(
data=request_data,
queryset=self.selection_filter.qs,
)
self.checkbox_filter = CheckboxCompensationTableFilter(
user=user,
data=request_data,
queryset=self.query_filter.qs,
)
# Overwrite final queryset as well
self.qs = self.checkbox_filter.qs
class CheckboxEcoAccountTableFilter(CheckboxTableFilter):
sr = django_filters.BooleanFilter(
method='filter_only_show_unrecorded',
method='_filter_only_show_unrecorded',
label=_("Show only unrecorded"),
label_suffix=_(""),
widget=forms.CheckboxInput(
attrs={
"class": "form-check-input",
}
)
widget=forms.CheckboxInput()
)
def filter_show_all(self, queryset, name, value) -> QuerySet:
def _filter_show_all(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_all' setting
Args:
@ -145,7 +90,7 @@ class CheckboxEcoAccountTableFilter(CheckboxTableFilter):
else:
return queryset
def filter_only_show_unrecorded(self, queryset, name, value) -> QuerySet:
def _filter_only_show_unrecorded(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_recorded' setting
Args:
@ -162,40 +107,3 @@ class CheckboxEcoAccountTableFilter(CheckboxTableFilter):
)
else:
return queryset
class SelectionEcoAccountTableFilter(ConservationOfficeTableFilterMixin):
""" Special selection table filter for eco accounts
EcoAccounts only need a selection filter for conservation office
"""
pass
class EcoAccountTableFilter(AbstractTableFilter):
""" TableFilter for eco accounts
"""
def __init__(self, user=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.user = user
qs = kwargs.get("queryset", None)
request_data = kwargs.get("data", None)
# Pipe the queryset through all needed filters
self.selection_filter = SelectionEcoAccountTableFilter(
data=request_data,
queryset=qs,
)
self.query_filter = QueryTableFilter(
data=request_data,
queryset=self.selection_filter.qs,
)
self.checkbox_filter = CheckboxEcoAccountTableFilter(
user=user,
data=request_data,
queryset=self.query_filter.qs,
)
# Overwrite the final queryset result
self.qs = self.checkbox_filter.qs

View File

@ -6,7 +6,7 @@ Created on: 04.12.20
"""
from dal import autocomplete
from user.models import User
from django.contrib.auth.models import User
from django.db import transaction
from django.urls import reverse_lazy, reverse
from django.utils.translation import gettext_lazy as _

View File

@ -8,7 +8,7 @@ Created on: 16.11.21
import shutil
from django.contrib import messages
from user.models import User
from django.contrib.auth.models import User
from django.db import models, transaction
from django.db.models import QuerySet, Sum
from django.http import HttpRequest

View File

@ -7,7 +7,7 @@ Created on: 16.11.21
"""
import shutil
from user.models import User
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator
from django.db import models, transaction

View File

@ -5,7 +5,7 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 01.12.20
"""
from user.models import User
from django.contrib.auth.models import User
from django.http import HttpRequest
from django.template.loader import render_to_string
from django.urls import reverse
@ -16,11 +16,11 @@ from django.utils.translation import gettext_lazy as _
from compensation.filters import CompensationTableFilter, EcoAccountTableFilter
from compensation.models import Compensation, EcoAccount
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
from konova.utils.tables import BaseTable, TableRenderMixin
from konova.utils.tables import BaseTable
import django_tables2 as tables
class CompensationTable(BaseTable, TableRenderMixin):
class CompensationTable(BaseTable):
id = tables.Column(
verbose_name=_("Identifier"),
orderable=True,
@ -67,8 +67,7 @@ class CompensationTable(BaseTable, TableRenderMixin):
data=request.GET,
queryset=qs,
)
kwargs["queryset"] = self.filter.qs
super().__init__(request, *args, **kwargs)
super().__init__(request, self.filter, *args, **kwargs)
def render_id(self, value, record: Compensation):
""" Renders the id column for a compensation
@ -162,7 +161,7 @@ class CompensationTable(BaseTable, TableRenderMixin):
return format_html(html)
class EcoAccountTable(BaseTable, TableRenderMixin):
class EcoAccountTable(BaseTable):
id = tables.Column(
verbose_name=_("Identifier"),
orderable=True,
@ -208,8 +207,7 @@ class EcoAccountTable(BaseTable, TableRenderMixin):
data=request.GET,
queryset=qs,
)
kwargs["queryset"] = self.filter.qs
super().__init__(request, *args, **kwargs)
super().__init__(request, self.filter, *args, **kwargs)
def render_id(self, value, record: EcoAccount):
""" Renders the id column for an eco account

View File

@ -58,8 +58,20 @@ class EcoAccountQualityChecker(CompensationQualityChecker):
self._check_deductable_surface()
self._check_responsible_data()
self._check_legal_data()
self._check_record_state()
super().run_check()
def _check_record_state(self):
""" Checks the data quality for recorded state
Returns:
"""
if self.obj.recorded is None:
self.messages.append(
_("Not recorded")
)
def _check_legal_data(self):
""" Checks the data quality for Legal

View File

@ -17,7 +17,6 @@ services:
command: gunicorn konova.wsgi:application --bind 0.0.0.0:8000
volumes:
- .:/konova
- konova_uploaded_files:/konova_uploaded_files
- static_file_volume:/konova/static # Point to the volume for static files. Shared with nginx service
expose:
- 8000
@ -40,7 +39,6 @@ services:
command: celery -A konova worker -l INFO
volumes:
- .:/konova
- konova_uploaded_files:/konova_uploaded_files
depends_on:
- konova
environment:
@ -69,5 +67,4 @@ networks:
name: postgis_nat_it_backend
volumes:
static_file_volume:
konova_uploaded_files:
static_file_volume:

View File

@ -5,6 +5,8 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 19.08.21
"""
from django.db.models import QuerySet
from compensation.filters import EcoAccountTableFilter

View File

@ -7,7 +7,7 @@ Created on: 06.10.21
"""
from dal import autocomplete
from django import forms
from user.models import User
from django.contrib.auth.models import User
from django.db import transaction
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _

View File

@ -14,12 +14,12 @@ from django.urls import reverse
import django_tables2 as tables
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
from konova.utils.tables import BaseTable, TableRenderMixin
from konova.utils.tables import BaseTable
from ema.filters import EmaTableFilter
from ema.models import Ema
class EmaTable(BaseTable, TableRenderMixin):
class EmaTable(BaseTable):
"""
Since EMA and compensation are basically the same, we can reuse CompensationTableFilter and extend the EMA filter
in the future by inheriting.
@ -65,8 +65,7 @@ class EmaTable(BaseTable, TableRenderMixin):
data=request.GET,
queryset=qs,
)
kwargs["queryset"] = self.filter.qs
super().__init__(request, *args, **kwargs)
super().__init__(request, self.filter, *args, **kwargs)
def render_id(self, value, record: Ema):
""" Renders the id column for a EMA

View File

@ -5,29 +5,119 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 22.07.21
"""
from konova.filters.table_filters import AbstractTableFilter, SelectionTableFilter, QueryTableFilter, CheckboxTableFilter
import django_filters
from django import forms
from django.contrib.auth.models import User
from django.db.models import QuerySet, Q
from django.utils.translation import gettext_lazy as _
from intervention.inputs import DummyFilterInput
from intervention.models import Intervention
class InterventionTableFilter(AbstractTableFilter):
def __init__(self, user=None, *args, **kwargs):
super().__init__(*args, **kwargs)
class InterventionTableFilter(django_filters.FilterSet):
""" TableFilter for Intervention model
"""
sa = django_filters.BooleanFilter(
method='_filter_show_all',
label=_("Show unshared"),
label_suffix=_(""),
widget=forms.CheckboxInput()
)
q = django_filters.Filter(
method='_filter_by_keyword',
# Since we use a custom search bar in the template, we need to 'render' this filter
# as 'anonymous' HiddenInput (no id, no name). This way our custom search bar's id and name won't be
# overwritten with these id and name (which would be equal)
# This way we can use the simple filter method mapping for a parameter without using a predefined widget!
widget=DummyFilterInput(),
)
sr = django_filters.BooleanFilter(
method='_filter_show_recorded',
label=_("Show recorded"),
label_suffix=_(""),
widget=forms.CheckboxInput()
)
# Gemarkung ##ToDo
g = django_filters.CharFilter(
field_name="name",
lookup_expr="icontains",
label=_(""),
label_suffix=_(""),
widget=forms.TextInput(
attrs={
"placeholder": _("District"),
"title": _("Search for district")
}
),
)
# Kreis
## ToDo
# Flur
## ToDo
# Zähler
## ToDo
# Nenner
## ToDo
class Meta:
model = Intervention
fields = []
def __init__(self, user: User, *args, **kwargs):
self.user = user
qs = kwargs.get("queryset", None)
request_data = kwargs.get("data", None)
super().__init__(*args, **kwargs)
# Pipe the queryset through all needed filters
self.selection_filter = SelectionTableFilter(
data=request_data,
queryset=qs,
)
self.query_filter = QueryTableFilter(
data=request_data,
queryset=self.selection_filter.qs,
)
self.checkbox_filter = CheckboxTableFilter(
user=user,
data=request_data,
queryset=self.query_filter.qs,
)
self.qs = self.checkbox_filter.qs
def _filter_by_keyword(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of search bar input
Args:
queryset ():
name ():
value ():
Returns:
"""
value = value.strip()
# build filter expression
q = Q(title__icontains=value) | Q(identifier__icontains=value)
return queryset.filter(q)
def _filter_show_all(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_all' setting
Args:
queryset ():
name ():
value ():
Returns:
"""
if not value:
return queryset.filter(
users__in=[self.user], # requesting user has access
)
else:
return queryset
def _filter_show_recorded(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_recorded' setting
Args:
queryset ():
name ():
value ():
Returns:
"""
if not value:
return queryset.filter(
recorded=None,
)
else:
return queryset

View File

@ -7,7 +7,7 @@ Created on: 02.12.20
"""
from dal import autocomplete
from django import forms
from user.models import User
from django.contrib.auth.models import User
from django.db import transaction
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _

View File

@ -6,7 +6,7 @@ Created on: 27.09.21
"""
from dal import autocomplete
from user.models import User
from django.contrib.auth.models import User
from django.db import transaction
from django import forms
from django.urls import reverse

View File

@ -8,7 +8,7 @@ Created on: 15.11.21
import shutil
from django.contrib import messages
from user.models import User
from django.contrib.auth.models import User
from django.db import models, transaction
from django.db.models import QuerySet
from django.http import HttpRequest

View File

@ -14,11 +14,11 @@ from django.utils.translation import gettext_lazy as _
from intervention.filters import InterventionTableFilter
from intervention.models import Intervention
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT, DEFAULT_DATE_FORMAT
from konova.utils.tables import BaseTable, TableRenderMixin
from konova.utils.tables import BaseTable
import django_tables2 as tables
class InterventionTable(BaseTable, TableRenderMixin):
class InterventionTable(BaseTable):
id = tables.Column(
verbose_name=_("Identifier"),
orderable=True,
@ -71,8 +71,7 @@ class InterventionTable(BaseTable, TableRenderMixin):
data=request.GET,
queryset=qs,
)
kwargs["queryset"] = self.filter.qs
super().__init__(request, *args, **kwargs)
super().__init__(request, self.filter, *args, **kwargs)
def render_id(self, value, record: Intervention):
""" Renders the id column for an intervention

View File

@ -6,7 +6,7 @@ Created on: 07.12.20
"""
from dal_select2.views import Select2QuerySetView, Select2GroupQuerySetView
from user.models import User
from django.contrib.auth.models import User
from django.db.models import Q
from codelist.models import KonovaCode

View File

@ -8,7 +8,7 @@ Created on: 16.11.20
from django.http import HttpRequest
from konova.sub_settings.context_settings import BASE_TITLE, HELP_LINK, BASE_FRONTEND_TITLE
from konova.sub_settings.django_settings import EMAIL_REPLY_TO
from konova.sub_settings.django_settings import LANGUAGE_CODE
class BaseContext:
@ -24,8 +24,7 @@ class BaseContext:
"language": request.LANGUAGE_CODE,
"user": request.user,
"current_role": None,
"help_link": HELP_LINK,
"CONTACT_MAIL": EMAIL_REPLY_TO,
"help_link": HELP_LINK
}
# Add additional context, derived from given parameters

View File

@ -1,7 +0,0 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 12.01.22
"""

View File

@ -1,406 +0,0 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 12.01.22
"""
import django_filters
from django import forms
from django.db.models import QuerySet, Q
from django.utils.translation import gettext_lazy as _
from dal_select2.widgets import ModelSelect2
from codelist.models import KonovaCode
from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_REGISTRATION_OFFICE_ID
from intervention.inputs import DummyFilterInput
from konova.models import Parcel, District
class KeywordTableFilterMixin(django_filters.FilterSet):
q = django_filters.Filter(
method='filter_by_keyword',
# Since we use a custom search bar in the template, we need to 'render' this filter
# as 'anonymous' HiddenInput (no id, no name). This way our custom search bar's id and name won't be
# overwritten with these id and name (which would be equal)
# This way we can use the simple filter method mapping for a parameter without using a predefined widget!
widget=DummyFilterInput(),
)
class Meta:
abstract = True
def filter_by_keyword(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of search bar input
Args:
queryset ():
name ():
value ():
Returns:
"""
value = value.strip()
# build filter expression
q = Q(title__icontains=value) | Q(identifier__icontains=value)
return queryset.filter(q)
class FileNumberTableFilterMixin(django_filters.FilterSet):
rf = django_filters.CharFilter(
method="filter_file_number",
label=_(""),
label_suffix=_(""),
widget=forms.TextInput(
attrs={
"placeholder": _("File number"),
"title": _("Search for file number"),
"class": "form-control",
}
),
)
def filter_file_number(self, queryset, name, value) -> QuerySet:
queryset = queryset.filter(
Q(responsible__registration_file_number__icontains=value) |
Q(responsible__conservation_file_number__icontains=value)
)
return queryset
class GeoReferencedTableFilterMixin(django_filters.FilterSet):
""" A mixin for AbstractTableFilter
Specialized on filtering GeoReferenced model types
"""
# Parcel gmrkng
di = django_filters.CharFilter(
method="filter_district",
label=_(""),
label_suffix=_(""),
widget=forms.TextInput(
attrs={
"placeholder": _("District"),
"title": _("Search for district"),
"class": "form-control",
}
),
)
# Parcel gmrkng
pg = django_filters.CharFilter(
method="filter_gmrkng",
label=_(""),
label_suffix=_(""),
widget=forms.TextInput(
attrs={
"placeholder": _("Parcel gmrkng"),
"title": _("Search for parcel gmrkng"),
"class": "form-control",
}
),
)
# Parcel
p = django_filters.CharFilter(
method="filter_parcel",
label=_(""),
label_suffix=_(""),
widget=forms.TextInput(
attrs={
"placeholder": _("Parcel"),
"title": _("Search for parcel"),
"class": "form-control",
}
),
)
# Parcel counter
pc = django_filters.CharFilter(
method="filter_parcel_counter",
label=_(""),
label_suffix=_(""),
widget=forms.TextInput(
attrs={
"placeholder": _("Parcel counter"),
"title": _("Search for parcel counter"),
"class": "form-control",
}
),
)
# Parcel counter
pn = django_filters.CharFilter(
method="filter_parcel_number",
label=_(""),
label_suffix=_(""),
widget=forms.TextInput(
attrs={
"placeholder": _("Parcel number"),
"title": _("Search for parcel number"),
"class": "form-control",
}
),
)
class Meta:
abstract = True
def _filter_parcel_reference(self, queryset, name, value, filter_value) -> QuerySet:
""" Filters the parcel entries by a given filter_value.
filter_value may already include further filter annotations like 'xy__icontains'
Args:
queryset ():
name ():
value ():
filter_value ():
Returns:
"""
_filter = {
filter_value: value
}
matching_parcels = Parcel.objects.filter(
**_filter
)
related_geoms = matching_parcels.values(
"geometries"
).distinct()
queryset = queryset.filter(
geometry__id__in=related_geoms
)
return queryset
def filter_district(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value for 'Gemarkung'
Args:
queryset ():
name ():
value ():
Returns:
"""
matching_districts = District.objects.filter(
krs=value
)
matching_parcels = Parcel.objects.filter(
district__in=matching_districts
)
related_geoms = matching_parcels.values(
"geometries"
).distinct()
queryset = queryset.filter(
geometry__id__in=related_geoms
)
return queryset
def filter_gmrkng(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value for 'Gemarkung'
Args:
queryset ():
name ():
value ():
Returns:
"""
queryset = self._filter_parcel_reference(queryset, name, value, "gmrkng__istartswith")
return queryset
def filter_parcel(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value for 'Parcel'
Args:
queryset ():
name ():
value ():
Returns:
"""
value = value.replace("-", "")
queryset = self._filter_parcel_reference(queryset, name, value, "flr")
return queryset
def filter_parcel_counter(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value for 'Parcel'
Args:
queryset ():
name ():
value ():
Returns:
"""
value = value.replace("-", "")
queryset = self._filter_parcel_reference(queryset, name, value, "flrstck_zhlr")
return queryset
def filter_parcel_number(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value for 'Parcel'
Args:
queryset ():
name ():
value ():
Returns:
"""
value = value.replace("-", "")
queryset = self._filter_parcel_reference(queryset, name, value, "flrstck_nnr")
return queryset
class ShareableTableFilterMixin(django_filters.FilterSet):
""" A mixin for AbstractTableFilter
Specialized on filtering shareable model types
"""
sa = django_filters.BooleanFilter(
method='filter_show_all',
label=_("Show unshared"),
label_suffix=_(""),
widget=forms.CheckboxInput(
attrs={
"class": "form-check-input",
}
)
)
class Meta:
abstract = True
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user", None)
if self.user is None:
raise AttributeError("User must be set for further filtering!")
super().__init__(*args, **kwargs)
def filter_show_all(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_all' setting
Args:
queryset ():
name ():
value ():
Returns:
"""
if not value:
return queryset.filter(
users__in=[self.user], # requesting user has access
)
else:
return queryset
class RecordableTableFilterMixin(django_filters.FilterSet):
""" A mixin for AbstractTableFilter
Specialized on filtering recordable model types
"""
sr = django_filters.BooleanFilter(
method='filter_show_recorded',
label=_("Show recorded"),
label_suffix=_(""),
widget=forms.CheckboxInput(
attrs={
"class": "form-check-input",
}
)
)
class Meta:
abstract = True
def filter_show_recorded(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_recorded' setting
Args:
queryset ():
name ():
value ():
Returns:
"""
if not value:
return queryset.filter(
recorded=None,
)
else:
return queryset
class RegistrationOfficeTableFilterMixin(django_filters.FilterSet):
""" A mixin for AbstractTableFilter
Specialized on filtering for related registration offices
"""
ro = django_filters.ModelChoiceFilter(
method="filter_reg_office",
label=_(""),
label_suffix=_(""),
queryset=KonovaCode.objects.filter(
is_archived=False,
is_leaf=True,
code_lists__in=[CODELIST_REGISTRATION_OFFICE_ID],
),
widget=ModelSelect2(
url="codes-registration-office-autocomplete",
attrs={
"data-placeholder": _("Registration office"),
"title": _("Search for registration office"),
"class": "",
}
),
)
def filter_reg_office(self, queryset, name, value):
qs = queryset.filter(
responsible__registration_office=value
)
return qs
class ConservationOfficeTableFilterMixin(django_filters.FilterSet):
""" A mixin for AbstractTableFilter
Specialized on filtering for related conservation offices
"""
co = django_filters.ModelChoiceFilter(
method="filter_cons_office",
label=_(""),
label_suffix=_(""),
queryset=KonovaCode.objects.filter(
is_archived=False,
is_leaf=True,
code_lists__in=[CODELIST_CONSERVATION_OFFICE_ID],
),
widget=ModelSelect2(
url="codes-conservation-office-autocomplete",
attrs={
"data-placeholder": _("Conservation office"),
"title": _("Search for conservation office"),
"class": "",
}
),
)
def filter_cons_office(self, queryset, name, value):
qs = queryset.filter(
responsible__conservation_office=value
)
return qs

View File

@ -1,50 +0,0 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 12.01.22
"""
import django_filters
from konova.filters.mixins import RegistrationOfficeTableFilterMixin, ConservationOfficeTableFilterMixin, \
KeywordTableFilterMixin, FileNumberTableFilterMixin, GeoReferencedTableFilterMixin, ShareableTableFilterMixin, \
RecordableTableFilterMixin
class AbstractTableFilter(django_filters.FilterSet):
""" Base TableFilter for all models
"""
selection_filter = None
query_filter = None
checkbox_filter = None
qs = None
user = None
class Meta:
abstract = True
class SelectionTableFilter(RegistrationOfficeTableFilterMixin,
ConservationOfficeTableFilterMixin):
""" TableFilter holding different filter options for selection related filtering
"""
pass
class QueryTableFilter(KeywordTableFilterMixin,
FileNumberTableFilterMixin,
GeoReferencedTableFilterMixin):
""" TableFilter holding different filter options for query related filtering
"""
pass
class CheckboxTableFilter(ShareableTableFilterMixin, RecordableTableFilterMixin):
""" TableFilter holding different filter options for checkbox related filtering
"""
pass

View File

@ -12,7 +12,7 @@ from bootstrap_modal_forms.forms import BSModalForm
from bootstrap_modal_forms.utils import is_ajax
from django import forms
from django.contrib import messages
from user.models import User
from django.contrib.auth.models import User
from django.contrib.gis.forms import OSMWidget, MultiPolygonField
from django.contrib.gis.geos import MultiPolygon
from django.db import transaction

View File

@ -7,8 +7,7 @@ Created on: 15.12.20
"""
from getpass import getpass
from user.models import User
from django.contrib.auth.models import Group
from django.contrib.auth.models import User, Group
from django.core.management import BaseCommand, call_command
from django.db import transaction

View File

@ -23,9 +23,10 @@ GROUPS_DATA = [
# Must match with UserNotificationEnum
USER_NOTIFICATIONS_NAMES = {
"NOTIFY_ON_SHARED_ACCESS_GAINED": _("On shared access gained"),
"NOTIFY_ON_NEW_RELATED_DATA": _("On new related data"),
"NOTIFY_ON_SHARE_LINK_DISABLED": _("On disabled share link"),
"NOTIFY_ON_SHARED_ACCESS_REMOVED": _("On shared access removed"),
"NOTIFY_ON_SHARED_DATA_RECORDED": _("On shared data recorded"),
"NOTIFY_ON_SHARED_DATA_DELETED": _("On shared data deleted"),
"NOTIFY_ON_SHARED_DATA_CHECKED": _("On shared data checked"),
"NOTIFY_ON_REGISTERED_DATA_EDITED": _("On registered data edited"),
}

View File

@ -110,13 +110,9 @@ class Geometry(BaseResource):
underlying_parcels = []
for result in fetched_parcels:
fetched_parcel = result[typename]
# There could be parcels which include the word 'Flur',
# which needs to be deleted and just keep the numerical values
## THIS CAN BE REMOVED IN THE FUTURE, WHEN 'Flur' WON'T OCCUR ANYMORE!
flr_val = fetched_parcel["ave:flur"].replace("Flur ", "")
parcel_obj = Parcel.objects.get_or_create(
gmrkng=fetched_parcel["ave:gemarkung"],
flr=flr_val,
flr=fetched_parcel["ave:flur"],
flrstck_nnr=fetched_parcel['ave:flstnrnen'],
flrstck_zhlr=fetched_parcel['ave:flstnrzae'],
)[0]

View File

@ -10,11 +10,7 @@ import uuid
from abc import abstractmethod
from django.contrib import messages
from konova.tasks import celery_send_mail_shared_access_removed, celery_send_mail_shared_access_given, \
celery_send_mail_shared_data_recorded, celery_send_mail_shared_data_unrecorded, \
celery_send_mail_shared_data_deleted, celery_send_mail_shared_data_checked
from user.models import User
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpRequest
from django.utils.timezone import now
@ -122,12 +118,6 @@ class BaseObject(BaseResource):
action = UserActionLogEntry.get_deleted_action(user)
self.deleted = action
self.log.add(action)
# Send mail
shared_users = self.users.all().values_list("id", flat=True)
for user_id in shared_users:
celery_send_mail_shared_data_deleted.delay(self.identifier, user_id)
self.save()
def add_log_entry(self, action: UserAction, user: User, comment: str):
@ -226,11 +216,6 @@ class RecordableObjectMixin(models.Model):
self.recorded = None
self.save()
self.log.add(action)
shared_users = self.users.all().values_list("id", flat=True)
for user_id in shared_users:
celery_send_mail_shared_data_unrecorded(self.identifier, user_id)
return action
def set_recorded(self, user: User):
@ -248,11 +233,6 @@ class RecordableObjectMixin(models.Model):
self.recorded = action
self.save()
self.log.add(action)
shared_users = self.users.all().values_list("id", flat=True)
for user_id in shared_users:
celery_send_mail_shared_data_recorded(self.identifier, user_id)
return action
def mark_as_edited(self, performing_user: User, request: HttpRequest = None, edit_comment: str = None):
@ -325,12 +305,6 @@ class CheckableObjectMixin(models.Model):
action = UserActionLogEntry.get_checked_action(user)
self.checked = action
self.save()
# Send mail
shared_users = self.users.all().values_list("id", flat=True)
for user_id in shared_users:
celery_send_mail_shared_data_checked.delay(self.identifier, user_id)
self.log.add(action)
return action
@ -437,17 +411,6 @@ class ShareableObjectMixin(models.Model):
users = User.objects.filter(
id__in=accessing_users
)
removed_users = self.users.all().exclude(
id__in=accessing_users
).values("id")
# Send mails
for user in removed_users:
celery_send_mail_shared_access_removed.delay(self.identifier, user["id"])
for user in new_accessing_users:
celery_send_mail_shared_access_given.delay(self.identifier, user)
# Set new shared users
self.share_with_list(users)

View File

@ -5,10 +5,9 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 17.08.21
"""
from django.contrib.auth.models import User
from simple_sso.sso_client.client import Client
from user.models import User
class KonovaSSOClient(Client):
""" Konova specialized derivate of general sso.Client.

View File

@ -130,7 +130,7 @@ DATABASES = {
# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
AUTH_USER_MODEL = "user.User"
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
@ -205,15 +205,9 @@ DEBUG_TOOLBAR_CONFIG = {
}
# EMAIL (see https://docs.djangoproject.com/en/dev/topics/email/)
# CHANGE_ME !!! ONLY FOR DEVELOPMENT !!!
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = '/tmp/app-messages' # change this to a proper location
DEFAULT_FROM_EMAIL = "service@ksp.de" # The default email address for the 'from' element
DEFAULT_FROM_EMAIL = "bot@arneo.de" # The default email address for the 'from' element
EMAIL_HOST = "localhost"
EMAIL_REPLY_TO = "ksp-servicestelle@sgdnord.rlp.de"
EMAIL_PORT = "25"
EMAIL_PORT = "1025"
#EMAIL_HOST_USER = ""
#EMAIL_HOST_PASSWORD = ""
EMAIL_USE_TLS = False

View File

@ -1,60 +1,14 @@
from time import sleep
from celery import shared_task
from django.core.exceptions import ObjectDoesNotExist
from konova.models import Geometry
@shared_task
def celery_update_parcels(geometry_id: str, recheck: bool = True):
from konova.models import Geometry
def celery_update_parcels(geometry_id: str):
try:
geom = Geometry.objects.get(id=geometry_id)
geom.parcels.clear()
geom.update_parcels()
except ObjectDoesNotExist:
if recheck:
sleep(5)
celery_update_parcels(geometry_id, False)
@shared_task
def celery_send_mail_shared_access_removed(obj_identifier, user_id):
from user.models import User
user = User.objects.get(id=user_id)
user.send_mail_shared_access_removed(obj_identifier)
@shared_task
def celery_send_mail_shared_access_given(obj_identifier, user_id):
from user.models import User
user = User.objects.get(id=user_id)
user.send_mail_shared_access_given(obj_identifier)
@shared_task
def celery_send_mail_shared_data_recorded(obj_identifier, user_id):
from user.models import User
user = User.objects.get(id=user_id)
user.send_mail_shared_data_recorded(obj_identifier)
@shared_task
def celery_send_mail_shared_data_unrecorded(obj_identifier, user_id):
from user.models import User
user = User.objects.get(id=user_id)
user.send_mail_shared_data_unrecorded(obj_identifier)
@shared_task
def celery_send_mail_shared_data_deleted(obj_identifier, user_id):
from user.models import User
user = User.objects.get(id=user_id)
user.send_mail_shared_data_deleted(obj_identifier)
@shared_task
def celery_send_mail_shared_data_checked(obj_identifier, user_id):
from user.models import User
user = User.objects.get(id=user_id)
user.send_mail_shared_data_checked(obj_identifier)
return

View File

@ -7,8 +7,7 @@ Created on: 26.10.21
"""
import datetime
from user.models import User
from django.contrib.auth.models import Group
from django.contrib.auth.models import User, Group
from django.contrib.gis.geos import MultiPolygon, Polygon
from django.core.exceptions import ObjectDoesNotExist
from django.test import TestCase, Client
@ -405,7 +404,6 @@ class AutocompleteTestCase(BaseViewTestCase):
cls.atcmplt_code_comp_process = reverse("codes-process-type-autocomplete")
cls.atcmplt_code_comp_reg_off = reverse("codes-registration-office-autocomplete")
cls.atcmplt_code_comp_cons_off = reverse("codes-conservation-office-autocomplete")
cls.atcmplt_code_share_user = reverse("share-user-autocomplete")
def _test_views_anonymous_user(self):
# ATTENTION: As of the current state of django-autocomplete-light, there is no way to check on authenticated
@ -423,7 +421,6 @@ class AutocompleteTestCase(BaseViewTestCase):
self.atcmplt_code_comp_process,
self.atcmplt_code_comp_reg_off,
self.atcmplt_code_comp_cons_off,
self.atcmplt_code_share_user,
]
self.assert_url_fail(client, urls)

View File

@ -57,7 +57,4 @@ urlpatterns = [
if DEBUG:
urlpatterns += [
path('__debug__/', include(debug_toolbar.urls)),
]
handler404 = "konova.views.get_404_view"
handler500 = "konova.views.get_500_view"
]

View File

@ -8,10 +8,8 @@ Created on: 09.11.20
import logging
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
from konova.sub_settings.django_settings import DEFAULT_FROM_EMAIL, EMAIL_REPLY_TO
from konova.sub_settings.django_settings import DEFAULT_FROM_EMAIL
logger = logging.getLogger(__name__)
@ -28,156 +26,27 @@ class Mailer:
auth_user = None
auth_password = None
def __init__(self, from_mail: str = DEFAULT_FROM_EMAIL, auth_user: str = None, auth_password: str = None, fail_silently: bool = False):
def __init__(self, to_mail: list, from_mail: str = DEFAULT_FROM_EMAIL, auth_user: str = None, auth_password: str = None, fail_silently: bool = False):
# Make sure given to_mail parameter is a list
if isinstance(to_mail, str):
to_mail = [to_mail]
self.from_mail = from_mail
self.to_mail = to_mail
self.fail_silently = fail_silently
self.auth_user = auth_user
self.auth_password = auth_password
def send(self, recipient_list: list, subject: str, msg: str):
def send(self, subject: str, msg: str):
"""
Sends a mail with subject and message
"""
return send_mail(
subject=subject,
message=None,
html_message=msg,
message=msg,
from_email=self.from_mail,
recipient_list=recipient_list,
recipient_list=self.to_mail,
fail_silently=self.fail_silently,
auth_user=self.auth_user,
auth_password=self.auth_password
)
def send_mail_shared_access_removed(self, obj_identifier, user):
""" Send a mail if user has no access to the object anymore
Args:
obj_identifier (str): The object identifier
Returns:
"""
context = {
"user": user,
"obj_identifier": obj_identifier,
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/sharing/shared_access_removed.html", context)
user_mail_address = [user.email]
self.send(
user_mail_address,
_("{} - Shared access removed").format(obj_identifier),
msg
)
def send_mail_shared_access_given(self, obj_identifier, user):
""" Send a mail if user just got access to the object
Args:
obj_identifier (str): The object identifier
Returns:
"""
context = {
"user": user,
"obj_identifier": obj_identifier,
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/sharing/shared_access_given.html", context)
user_mail_address = [user.email]
self.send(
user_mail_address,
_("{} - Shared access given").format(obj_identifier),
msg
)
def send_mail_shared_data_recorded(self, obj_identifier, user):
""" Send a mail if the user's shared data has just been unrecorded
Args:
obj_identifier (str): The object identifier
Returns:
"""
context = {
"user": user,
"obj_identifier": obj_identifier,
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/recording/shared_data_recorded.html", context)
user_mail_address = [user.email]
self.send(
user_mail_address,
_("{} - Shared data recorded").format(obj_identifier),
msg
)
def send_mail_shared_data_unrecorded(self, obj_identifier, user):
""" Send a mail if the user's shared data has just been unrecorded
Args:
obj_identifier (str): The object identifier
Returns:
"""
context = {
"user": user,
"obj_identifier": obj_identifier,
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/recording/shared_data_unrecorded.html", context)
user_mail_address = [user.email]
self.send(
user_mail_address,
_("{} - Shared data unrecorded").format(obj_identifier),
msg
)
def send_mail_shared_data_deleted(self, obj_identifier, user):
""" Send a mail if shared data has just been deleted
Args:
obj_identifier (str): The object identifier
Returns:
"""
context = {
"user": user,
"obj_identifier": obj_identifier,
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/deleting/shared_data_deleted.html", context)
user_mail_address = [user.email]
self.send(
user_mail_address,
_("{} - Shared data deleted").format(obj_identifier),
msg
)
def send_mail_shared_data_checked(self, obj_identifier, user):
""" Send a mail if shared data just has been checked
Args:
obj_identifier (str): The object identifier
Returns:
"""
context = {
"user": user,
"obj_identifier": obj_identifier,
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/checking/shared_data_checked.html", context)
user_mail_address = [user.email]
self.send(
user_mail_address,
_("{} - Shared data checked").format(obj_identifier),
msg
)
)

View File

@ -8,7 +8,7 @@ Created on: 17.08.21
from collections import Iterable
import requests
from user.models import User
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
from konova.settings import SSO_SERVER_BASE, SSO_PUBLIC_KEY, PROXIES

View File

@ -5,13 +5,15 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 25.11.20
"""
import uuid
from django import forms
from django.core.paginator import PageNotAnInteger, EmptyPage
from django.http import HttpRequest
from django.utils.html import format_html
import django_tables2 as tables
from konova.models import BaseObject
from konova.forms import BaseForm
from konova.settings import PAGE_SIZE_DEFAULT, PAGE_PARAM, RESULTS_PER_PAGE_PARAM, PAGE_SIZE_OPTIONS
@ -29,8 +31,10 @@ class BaseTable(tables.tables.Table):
"class": "table table-hover table-responsive-md table-responsive-sm",
}
def __init__(self, request: HttpRequest = None, queryset=None, *args, **kwargs):
def __init__(self, request: HttpRequest = None, filter_set=None, queryset=None, *args, **kwargs):
self.user = request.user or None
if filter_set is not None:
queryset = filter_set.qs
kwargs["data"] = queryset
kwargs["request"] = request
super().__init__(*args, **kwargs)
@ -145,21 +149,22 @@ class BaseTable(tables.tables.Table):
)
class TableRenderMixin:
""" Holds different render methods for general purposes
class ChoicesColumnForm(BaseForm):
select = forms.ChoiceField(
choices=[],
label="",
label_suffix="",
widget=forms.Select(
attrs={
"onchange": "submit();",
}
)
)
"""
def render_t(self, value, record: BaseObject):
""" Renders a BaseObject title
Args:
value ():
record ():
Returns:
"""
max_length = 75
if len(value) > max_length:
value = f"{value[:max_length]}..."
return value
def __init__(self, *args, **kwargs):
self.action_url = kwargs.pop("action_url", None)
self.choices = kwargs.pop("choices", [])
super().__init__(*args, **kwargs)
self.auto_id += "_" + str(uuid.uuid4())
if len(self.choices) > 0:
self.fields["select"].choices = self.choices

View File

@ -5,7 +5,7 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 02.07.21
"""
from user.models import User
from django.contrib.auth.models import User
from konova.settings import ETS_GROUP, ZB_GROUP

View File

@ -6,7 +6,6 @@ Created on: 17.12.21
"""
from abc import abstractmethod
from time import sleep
import requests
import xmltodict
@ -123,7 +122,6 @@ class ParcelWFSFetcher(AbstractWFSFetcher):
spatial_operator: str = "Intersects",
filter_srid: str = None,
start_index: int = 0,
rerun_on_exception: bool = True
):
""" Fetches features from the WFS using POST
@ -161,23 +159,6 @@ class ParcelWFSFetcher(AbstractWFSFetcher):
{},
)
# Check if collection is an exception and does not contain the requested data
if len(collection) == 0:
exception = content.get(
"ows:ExceptionReport",
{}
)
if len(exception) > 0 and rerun_on_exception:
# Wait a second before another try
sleep(1)
self.get_features(
typenames,
spatial_operator,
filter_srid,
start_index,
rerun_on_exception=False
)
members = collection.get(
"wfs:member",
[],

View File

@ -113,31 +113,4 @@ def remove_deadline_view(request: HttpRequest, id:str):
return form.process_request(
request,
msg_success=_("Deadline removed")
)
def get_404_view(request: HttpRequest, exception=None):
""" Returns a 404 handling view
Args:
request ():
exception ():
Returns:
"""
context = BaseContext.context
return render(request, "404.html", context, status=404)
def get_500_view(request: HttpRequest):
""" Returns a 404 handling view
Args:
request ():
Returns:
"""
context = BaseContext.context
return render(request, "500.html", context, status=500)
)

Binary file not shown.

View File

@ -3,21 +3,14 @@
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#: compensation/filters.py:122 compensation/forms/modalForms.py:34
#: compensation/filters.py:71 compensation/forms/modalForms.py:34
#: compensation/forms/modalForms.py:45 compensation/forms/modalForms.py:61
#: compensation/forms/modalForms.py:238 compensation/forms/modalForms.py:316
#: intervention/filters.py:26 intervention/filters.py:40
#: intervention/filters.py:47 intervention/filters.py:48
#: intervention/forms/forms.py:52 intervention/forms/forms.py:154
#: intervention/forms/forms.py:166 intervention/forms/modalForms.py:125
#: intervention/forms/modalForms.py:138 intervention/forms/modalForms.py:151
#: konova/filters/mixins.py:53 konova/filters/mixins.py:54
#: konova/filters/mixins.py:81 konova/filters/mixins.py:82
#: konova/filters/mixins.py:94 konova/filters/mixins.py:95
#: konova/filters/mixins.py:107 konova/filters/mixins.py:108
#: konova/filters/mixins.py:120 konova/filters/mixins.py:121
#: konova/filters/mixins.py:134 konova/filters/mixins.py:135
#: konova/filters/mixins.py:270 konova/filters/mixins.py:315
#: konova/filters/mixins.py:353 konova/filters/mixins.py:354
#: konova/filters/mixins.py:385 konova/filters/mixins.py:386
#: konova/forms.py:140 konova/forms.py:241 konova/forms.py:312
#: konova/forms.py:339 konova/forms.py:349 konova/forms.py:362
#: konova/forms.py:374 konova/forms.py:392 user/forms.py:38
@ -26,7 +19,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-12 16:43+0100\n"
"POT-Creation-Date: 2022-01-07 15:32+0100\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"
@ -47,12 +40,12 @@ msgstr "Bis"
#: analysis/forms.py:47 compensation/forms/forms.py:77
#: compensation/templates/compensation/detail/eco_account/view.html:58
#: compensation/templates/compensation/report/eco_account/report.html:16
#: compensation/utils/quality.py:100 ema/templates/ema/detail/view.html:49
#: compensation/utils/quality.py:112 ema/templates/ema/detail/view.html:49
#: ema/templates/ema/report/report.html:16 ema/utils/quality.py:26
#: intervention/forms/forms.py:100
#: intervention/templates/intervention/detail/view.html:56
#: intervention/templates/intervention/report/report.html:37
#: intervention/utils/quality.py:49 konova/filters/mixins.py:395
#: intervention/utils/quality.py:49
msgid "Conservation office"
msgstr "Eintragungsstelle"
@ -140,7 +133,7 @@ msgstr "Zuständigkeitsbereich"
#: compensation/templates/compensation/detail/compensation/view.html:63
#: intervention/tables.py:33
#: intervention/templates/intervention/detail/view.html:68
#: user/models/user_action.py:18
#: user/models/user_action.py:19
msgid "Checked"
msgstr "Geprüft"
@ -152,14 +145,14 @@ msgstr "Geprüft"
#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:9
#: analysis/templates/analysis/reports/includes/intervention/laws.html:20
#: analysis/templates/analysis/reports/includes/old_data/amount.html:18
#: compensation/tables.py:41 compensation/tables.py:182
#: compensation/tables.py:41 compensation/tables.py:181
#: compensation/templates/compensation/detail/compensation/view.html:77
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31
#: compensation/templates/compensation/detail/eco_account/view.html:44
#: ema/tables.py:38 ema/templates/ema/detail/view.html:35
#: intervention/tables.py:39
#: intervention/templates/intervention/detail/view.html:82
#: user/models/user_action.py:19
#: user/models/user_action.py:20
msgid "Recorded"
msgstr "Verzeichnet"
@ -238,7 +231,7 @@ msgstr "Kompensationsart"
#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:15
#: analysis/templates/analysis/reports/includes/old_data/amount.html:29
#: compensation/tables.py:85
#: compensation/tables.py:84
#: compensation/templates/compensation/detail/compensation/view.html:19
#: konova/templates/konova/home.html:49 templates/navbars/navbar.html:28
msgid "Compensation"
@ -283,14 +276,14 @@ msgstr "Typ"
#: analysis/templates/analysis/reports/includes/old_data/amount.html:24
#: intervention/forms/modalForms.py:306 intervention/forms/modalForms.py:313
#: intervention/tables.py:89
#: intervention/tables.py:88
#: intervention/templates/intervention/detail/view.html:19
#: konova/templates/konova/home.html:11 templates/navbars/navbar.html:22
msgid "Intervention"
msgstr "Eingriff"
#: analysis/templates/analysis/reports/includes/old_data/amount.html:34
#: compensation/tables.py:226
#: compensation/tables.py:224
#: compensation/templates/compensation/detail/eco_account/view.html:19
#: intervention/forms/modalForms.py:279 intervention/forms/modalForms.py:286
#: konova/templates/konova/home.html:88 templates/navbars/navbar.html:34
@ -305,12 +298,12 @@ msgstr "Altfälle"
msgid "Before"
msgstr "Vor"
#: compensation/filters.py:121
#: compensation/filters.py:70
msgid "Show only unrecorded"
msgstr "Nur unverzeichnete anzeigen"
#: compensation/forms/forms.py:32 compensation/tables.py:25
#: compensation/tables.py:167 ema/tables.py:28 intervention/forms/forms.py:26
#: compensation/tables.py:166 ema/tables.py:28 intervention/forms/forms.py:26
#: intervention/tables.py:23
#: intervention/templates/intervention/detail/includes/compensations.html:30
msgid "Identifier"
@ -321,7 +314,7 @@ msgid "Generated automatically"
msgstr "Automatisch generiert"
#: compensation/forms/forms.py:44 compensation/tables.py:30
#: compensation/tables.py:172
#: compensation/tables.py:171
#: compensation/templates/compensation/detail/compensation/includes/documents.html:28
#: compensation/templates/compensation/detail/compensation/view.html:31
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:28
@ -374,7 +367,7 @@ msgstr "Zusätzlicher Kommentar"
#: compensation/forms/forms.py:93
#: compensation/templates/compensation/detail/eco_account/view.html:62
#: compensation/templates/compensation/report/eco_account/report.html:20
#: compensation/utils/quality.py:102 ema/templates/ema/detail/view.html:53
#: compensation/utils/quality.py:114 ema/templates/ema/detail/view.html:53
#: ema/templates/ema/report/report.html:20 ema/utils/quality.py:28
#: intervention/forms/forms.py:128
#: intervention/templates/intervention/detail/view.html:60
@ -434,7 +427,7 @@ msgstr "Neue Kompensation"
msgid "Edit compensation"
msgstr "Bearbeite Kompensation"
#: compensation/forms/forms.py:302 compensation/utils/quality.py:84
#: compensation/forms/forms.py:302 compensation/utils/quality.py:96
msgid "Available Surface"
msgstr "Verfügbare Fläche"
@ -444,7 +437,7 @@ msgstr "Die für Abbuchungen zur Verfügung stehende Menge"
#: compensation/forms/forms.py:314
#: compensation/templates/compensation/detail/eco_account/view.html:66
#: compensation/utils/quality.py:72
#: compensation/utils/quality.py:84
msgid "Agreement date"
msgstr "Vereinbarungsdatum"
@ -640,65 +633,65 @@ msgstr ""
"Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar einstellen "
"wollen. Kontaktieren Sie die für die Abbuchungen verantwortlichen Nutzer!"
#: compensation/tables.py:47 compensation/tables.py:188 ema/tables.py:44
#: compensation/tables.py:47 compensation/tables.py:187 ema/tables.py:44
#: intervention/tables.py:51
msgid "Editable"
msgstr "Freigegeben"
#: compensation/tables.py:53 compensation/tables.py:194 ema/tables.py:50
#: compensation/tables.py:53 compensation/tables.py:193 ema/tables.py:50
#: intervention/tables.py:57
msgid "Last edit"
msgstr "Zuletzt bearbeitet"
#: compensation/tables.py:85 compensation/tables.py:226 ema/tables.py:83
#: intervention/tables.py:89
#: compensation/tables.py:84 compensation/tables.py:224 ema/tables.py:82
#: intervention/tables.py:88
msgid "Open {}"
msgstr "Öffne {}"
#: compensation/tables.py:106 intervention/tables.py:108
#: compensation/tables.py:105 intervention/tables.py:107
msgid "Not checked yet"
msgstr "Noch nicht geprüft"
#: compensation/tables.py:111 intervention/tables.py:113
#: compensation/tables.py:110 intervention/tables.py:112
msgid "Checked on {} by {}"
msgstr "Am {} von {} geprüft worden"
#: compensation/tables.py:130
#: compensation/tables.py:129
#: compensation/templates/compensation/detail/compensation/view.html:80
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:56
#: compensation/templates/compensation/detail/eco_account/view.html:47
#: ema/tables.py:102 ema/templates/ema/detail/view.html:38
#: intervention/tables.py:132
#: ema/tables.py:101 ema/templates/ema/detail/view.html:38
#: intervention/tables.py:131
#: intervention/templates/intervention/detail/view.html:85
msgid "Not recorded yet"
msgstr "Noch nicht verzeichnet"
#: compensation/tables.py:135 compensation/tables.py:264 ema/tables.py:107
#: intervention/tables.py:137
#: compensation/tables.py:134 compensation/tables.py:262 ema/tables.py:106
#: intervention/tables.py:136
msgid "Recorded on {} by {}"
msgstr "Am {} von {} verzeichnet worden"
#: compensation/tables.py:159 compensation/tables.py:286 ema/tables.py:130
#: intervention/tables.py:160
#: compensation/tables.py:158 compensation/tables.py:284 ema/tables.py:129
#: intervention/tables.py:159
msgid "Full access granted"
msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden"
#: compensation/tables.py:159 compensation/tables.py:286 ema/tables.py:130
#: intervention/tables.py:160
#: compensation/tables.py:158 compensation/tables.py:284 ema/tables.py:129
#: intervention/tables.py:159
msgid "Access not granted"
msgstr "Nicht freigegeben - Datensatz nur lesbar"
#: compensation/tables.py:177
#: compensation/tables.py:176
#: compensation/templates/compensation/detail/eco_account/view.html:35
#: konova/templates/konova/widgets/progressbar.html:3
msgid "Available"
msgstr "Verfügbar"
#: compensation/tables.py:203
#: compensation/tables.py:202
msgid "Eco Accounts"
msgstr "Ökokonten"
#: compensation/tables.py:259
#: compensation/tables.py:257
msgid "Not recorded yet. Can not be used for deductions, yet."
msgstr ""
"Noch nicht verzeichnet. Kann noch nicht für Abbuchungen genutzt werden."
@ -962,7 +955,7 @@ msgstr "Eingriffskennung"
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:37
#: intervention/templates/intervention/detail/includes/deductions.html:34
#: user/models/user_action.py:21
#: user/models/user_action.py:22
msgid "Created"
msgstr "Erstellt"
@ -1040,17 +1033,21 @@ msgstr "-"
msgid "States unequal"
msgstr "Ungleiche Zustandsflächenmengen"
#: compensation/utils/quality.py:74 intervention/utils/quality.py:84
#: compensation/utils/quality.py:72
msgid "Not recorded"
msgstr "Noch nicht verzeichnet"
#: compensation/utils/quality.py:86 intervention/utils/quality.py:84
msgid "Legal data"
msgstr "Rechtliche Daten"
#: compensation/utils/quality.py:88
#: compensation/utils/quality.py:100
msgid "Deductable surface can not be larger than state surface"
msgstr ""
"Die abbuchbare Fläche darf die Gesamtfläche der Zielzustände nicht "
"überschreiten"
#: compensation/utils/quality.py:104 ema/utils/quality.py:30
#: compensation/utils/quality.py:116 ema/utils/quality.py:30
#: intervention/utils/quality.py:55
msgid "Responsible data"
msgstr "Daten zu den verantwortlichen Stellen"
@ -1064,7 +1061,7 @@ msgid "Compensation {} edited"
msgstr "Kompensation {} bearbeitet"
#: compensation/views/compensation.py:230 compensation/views/eco_account.py:309
#: ema/views.py:183 intervention/views.py:478
#: ema/views.py:183 intervention/views.py:477
msgid "Log"
msgstr "Log"
@ -1119,36 +1116,36 @@ msgid "Deduction removed"
msgstr "Abbuchung entfernt"
#: compensation/views/eco_account.py:330 ema/views.py:263
#: intervention/views.py:520
#: intervention/views.py:519
msgid "{} unrecorded"
msgstr "{} entzeichnet"
#: compensation/views/eco_account.py:330 ema/views.py:263
#: intervention/views.py:520
#: intervention/views.py:519
msgid "{} recorded"
msgstr "{} verzeichnet"
#: compensation/views/eco_account.py:531 intervention/views.py:501
#: compensation/views/eco_account.py:531 intervention/views.py:500
msgid "Deduction added"
msgstr "Abbuchung hinzugefügt"
#: compensation/views/eco_account.py:616 ema/views.py:520
#: intervention/views.py:376
#: intervention/views.py:375
msgid "{} has already been shared with you"
msgstr "{} wurde bereits für Sie freigegeben"
#: compensation/views/eco_account.py:621 ema/views.py:525
#: intervention/views.py:381
#: intervention/views.py:380
msgid "{} has been shared with you"
msgstr "{} ist nun für Sie freigegeben"
#: compensation/views/eco_account.py:628 ema/views.py:532
#: intervention/views.py:388
#: intervention/views.py:387
msgid "Share link invalid"
msgstr "Freigabelink ungültig"
#: compensation/views/eco_account.py:651 ema/views.py:555
#: intervention/views.py:411
#: intervention/views.py:410
msgid "Share settings updated"
msgstr "Freigabe Einstellungen aktualisiert"
@ -1180,7 +1177,7 @@ msgstr ""
"Maßnahmen aus Ersatzzahlungen, die nach 2015 rechtskräftig wurden, werden "
"durch die Stiftung Natur und Umwelt verwaltet."
#: ema/tables.py:83 templates/navbars/navbar.html:43
#: ema/tables.py:82 templates/navbars/navbar.html:43
msgid "EMA"
msgstr ""
@ -1200,6 +1197,22 @@ msgstr "EMA {} bearbeitet"
msgid "EMA removed"
msgstr "EMA entfernt"
#: intervention/filters.py:25
msgid "Show unshared"
msgstr "Nicht freigegebene anzeigen"
#: intervention/filters.py:39
msgid "Show recorded"
msgstr "Verzeichnete anzeigen"
#: intervention/filters.py:51
msgid "District"
msgstr "Gemarkung"
#: intervention/filters.py:52
msgid "Search for district"
msgstr "Nach Gemarkung suchen"
#: intervention/forms/forms.py:44
msgid "Construction XY; Location ABC"
msgstr "Bauvorhaben XY; Flur ABC"
@ -1218,7 +1231,7 @@ msgstr "Mehrfachauswahl möglich"
#: intervention/forms/forms.py:84
#: intervention/templates/intervention/detail/view.html:48
#: intervention/templates/intervention/report/report.html:29
#: intervention/utils/quality.py:46 konova/filters/mixins.py:363
#: intervention/utils/quality.py:46
msgid "Registration office"
msgstr "Zulassungsbehörde"
@ -1369,11 +1382,11 @@ msgstr ""
msgid "Revocation"
msgstr "Widerspruch"
#: intervention/tables.py:177
#: intervention/tables.py:176
msgid "No revocation"
msgstr "Kein Widerspruch"
#: intervention/tables.py:183
#: intervention/tables.py:182
msgid "Revocation from {}, added on {} by {}"
msgstr "Widerspruch vom {}, am {} von {} hinzugefügt"
@ -1463,31 +1476,31 @@ msgstr ""
msgid "Intervention {} added"
msgstr "Eingriff {} hinzugefügt"
#: intervention/views.py:246
#: intervention/views.py:245
msgid "This intervention has {} revocations"
msgstr "Dem Eingriff liegen {} Widersprüche vor"
#: intervention/views.py:294
#: intervention/views.py:293
msgid "Intervention {} edited"
msgstr "Eingriff {} bearbeitet"
#: intervention/views.py:329
#: intervention/views.py:328
msgid "{} removed"
msgstr "{} entfernt"
#: intervention/views.py:350
#: intervention/views.py:349
msgid "Revocation removed"
msgstr "Widerspruch entfernt"
#: intervention/views.py:432
#: intervention/views.py:431
msgid "Check performed"
msgstr "Prüfung durchgeführt"
#: intervention/views.py:454
#: intervention/views.py:453
msgid "Revocation added"
msgstr "Widerspruch hinzugefügt"
#: intervention/views.py:525
#: intervention/views.py:524
msgid "There are errors on this intervention:"
msgstr "Es liegen Fehler in diesem Eingriff vor:"
@ -1508,73 +1521,6 @@ msgstr ""
"somit nichts eingeben, bearbeiten oder sonstige Aktionen ausführen. "
"Kontaktieren Sie bitte einen Administrator. +++"
#: konova/filters/mixins.py:57
msgid "File number"
msgstr "Aktenzeichen"
#: konova/filters/mixins.py:58
msgid "Search for file number"
msgstr "Nach Aktenzeichen suchen"
#: konova/filters/mixins.py:85
msgid "District"
msgstr "Kreis"
#: konova/filters/mixins.py:86
msgid "Search for district"
msgstr "Nach Kreis suchen"
#: konova/filters/mixins.py:98
msgid "Parcel gmrkng"
msgstr "Gemarkung"
#: konova/filters/mixins.py:99
msgid "Search for parcel gmrkng"
msgstr "Nach Gemarkung suchen"
#: konova/filters/mixins.py:111
#: konova/templates/konova/includes/parcels.html:18
msgid "Parcel"
msgstr "Flur"
#: konova/filters/mixins.py:112
msgid "Search for parcel"
msgstr "Nach Flur suchen"
#: konova/filters/mixins.py:124
#: konova/templates/konova/includes/parcels.html:19
msgid "Parcel counter"
msgstr "Flurstückzähler"
#: konova/filters/mixins.py:125
msgid "Search for parcel counter"
msgstr "Nach Flurstückzähler suchen"
#: konova/filters/mixins.py:138
#: konova/templates/konova/includes/parcels.html:20
msgid "Parcel number"
msgstr "Flurstücknenner"
#: konova/filters/mixins.py:139
msgid "Search for parcel number"
msgstr "Nach Flurstücknenner suchen"
#: konova/filters/mixins.py:269
msgid "Show unshared"
msgstr "Nicht freigegebene anzeigen"
#: konova/filters/mixins.py:314
msgid "Show recorded"
msgstr "Verzeichnete anzeigen"
#: konova/filters/mixins.py:364
msgid "Search for registration office"
msgstr "Nach Zulassungsbehörde suchen"
#: konova/filters/mixins.py:396
msgid "Search for conservation office"
msgstr "Nch Eintragungsstelle suchen"
#: konova/forms.py:37 templates/form/collapsable/form.html:62
msgid "Save"
msgstr "Speichern"
@ -1655,24 +1601,28 @@ msgstr ""
"Ich, {} {}, bestätige, dass diese Daten wieder entzeichnet werden müssen."
#: konova/management/commands/setup_data.py:26
msgid "On shared access gained"
msgstr "Wenn mir eine Freigabe zu Daten erteilt wird"
msgid "On new related data"
msgstr "Wenn neue Daten für mich angelegt werden"
#: konova/management/commands/setup_data.py:27
msgid "On disabled share link"
msgstr "Wenn ein Freigabelink deaktiviert wird"
#: konova/management/commands/setup_data.py:28
msgid "On shared access removed"
msgstr "Wenn mir eine Freigabe zu Daten entzogen wird"
#: konova/management/commands/setup_data.py:28
#: konova/management/commands/setup_data.py:29
msgid "On shared data recorded"
msgstr "Wenn meine freigegebenen Daten verzeichnet wurden"
#: konova/management/commands/setup_data.py:29
#: konova/management/commands/setup_data.py:30
msgid "On shared data deleted"
msgstr "Wenn meine freigegebenen Daten gelöscht wurden"
#: konova/management/commands/setup_data.py:30
msgid "On shared data checked"
msgstr "Wenn meine freigegebenen Daten geprüft wurden"
#: konova/management/commands/setup_data.py:31
msgid "On registered data edited"
msgstr "Wenn meine freigegebenen Daten bearbeitet wurden"
#: konova/models/deadline.py:18
msgid "Finished"
@ -1737,6 +1687,18 @@ msgstr "Kreis"
msgid "Gemarkung"
msgstr "Gemarkung"
#: konova/templates/konova/includes/parcels.html:18
msgid "Parcel"
msgstr "Flur"
#: konova/templates/konova/includes/parcels.html:19
msgid "Parcel counter"
msgstr "Flurstückzähler"
#: konova/templates/konova/includes/parcels.html:20
msgid "Parcel number"
msgstr "Flurstücknenner"
#: konova/templates/konova/widgets/generate-content-input.html:6
msgid "Generate new"
msgstr "Neu generieren"
@ -1753,30 +1715,6 @@ msgstr "In Zwischenablage kopiert"
msgid "Document '{}' deleted"
msgstr "Dokument '{}' gelöscht"
#: konova/utils/mailer.py:70
msgid "{} - Shared access removed"
msgstr "{} - Zugriff entzogen"
#: konova/utils/mailer.py:92
msgid "{} - Shared access given"
msgstr "{} - Zugriff freigegeben"
#: konova/utils/mailer.py:114
msgid "{} - Shared data recorded"
msgstr "{} - Freigegebene Daten verzeichnet"
#: konova/utils/mailer.py:136
msgid "{} - Shared data unrecorded"
msgstr "{} - Freigegebene Daten entzeichnet"
#: konova/utils/mailer.py:158
msgid "{} - Shared data deleted"
msgstr "{} - Freigegebene Daten gelöscht"
#: konova/utils/mailer.py:180
msgid "{} - Shared data checked"
msgstr "{} - Freigegebene Daten geprüft"
#: konova/utils/message_templates.py:11
msgid "There was an error on this form."
msgstr "Es gab einen Fehler im Formular."
@ -1891,173 +1829,6 @@ msgstr "Alle"
msgid "News"
msgstr "Neuigkeiten"
#: templates/404.html:7
msgid "Not found"
msgstr "Nicht gefunden"
#: templates/404.html:10
msgid "The requested data does not exist."
msgstr "Die angeforderten Daten existieren nicht."
#: templates/500.html:7
msgid "Server Error"
msgstr ""
#: templates/500.html:10
msgid "Something happened. We are working on it!"
msgstr "Irgendetwas ist passiert. Wir arbeiten daran!"
#: templates/email/checking/shared_data_checked.html:4
msgid "Shared data checked"
msgstr "Freigegebene Daten geprüft"
#: templates/email/checking/shared_data_checked.html:8
#: templates/email/deleting/shared_data_deleted.html:8
#: templates/email/recording/shared_data_recorded.html:8
#: templates/email/recording/shared_data_unrecorded.html:8
#: templates/email/sharing/shared_access_given.html:8
#: templates/email/sharing/shared_access_removed.html:8
msgid "Hello "
msgstr "Hallo "
#: templates/email/checking/shared_data_checked.html:10
msgid "the following dataset has just been checked"
msgstr "der folgende Datensatz wurde soeben geprüft "
#: templates/email/checking/shared_data_checked.html:14
msgid ""
"This means, the responsible registration office just confirmed the "
"correctness of this dataset."
msgstr ""
"Das bedeutet, dass die zuständige Zulassungsbehörde die Korrektheit des "
"Datensatzes soeben bestätigt hat."
#: templates/email/checking/shared_data_checked.html:17
#: templates/email/deleting/shared_data_deleted.html:17
#: templates/email/recording/shared_data_recorded.html:17
#: templates/email/recording/shared_data_unrecorded.html:17
#: templates/email/sharing/shared_access_given.html:18
#: templates/email/sharing/shared_access_removed.html:18
msgid "Best regards"
msgstr "Beste Grüße"
#: templates/email/deleting/shared_data_deleted.html:4
msgid "Shared data deleted"
msgstr "Freigegebene Daten gelöscht"
#: templates/email/deleting/shared_data_deleted.html:10
msgid "the following dataset has just been deleted"
msgstr "der folgende Datensatz wurde soeben gelöscht "
#: templates/email/deleting/shared_data_deleted.html:14
msgid ""
"If this should not have been happened, please contact us. See the signature "
"for details."
msgstr ""
"Falls das nicht hätte passieren dürfen, kontaktieren Sie uns bitte. In der E-"
"mail Signatur finden Sie weitere Kontaktinformationen."
#: templates/email/recording/shared_data_recorded.html:4
msgid "Shared data recorded"
msgstr "Freigegebene Daten verzeichnet"
#: templates/email/recording/shared_data_recorded.html:10
msgid "the following dataset has just been recorded"
msgstr "der folgende Datensatz wurde soeben verzeichnet "
#: templates/email/recording/shared_data_recorded.html:14
msgid "This means the data is now publicly available, e.g. in LANIS"
msgstr ""
"Das bedeutet, dass die Daten nun öffentlich verfügbar sind, z.B. im LANIS."
#: templates/email/recording/shared_data_recorded.html:24
msgid ""
"Please note: Recorded intervention means the compensations are recorded as "
"well."
msgstr ""
"Bitte beachten Sie: Verzeichnete Eingriffe bedeuten, dass auch die "
"zugehörigen Kompensationen automatisch verzeichnet sind."
#: templates/email/recording/shared_data_unrecorded.html:4
msgid "Shared data unrecorded"
msgstr "Freigegebene Daten entzeichnet"
#: templates/email/recording/shared_data_unrecorded.html:10
msgid "the following dataset has just been unrecorded"
msgstr "der folgende Datensatz wurde soeben entzeichnet "
#: templates/email/recording/shared_data_unrecorded.html:14
msgid "This means the data is no longer publicly available."
msgstr "Das bedeutet, dass die Daten nicht länger öffentlich verfügbar sind."
#: templates/email/recording/shared_data_unrecorded.html:24
msgid ""
"Please note: Unrecorded intervention means the compensations are unrecorded "
"as well."
msgstr ""
"Bitte beachten Sie: Entzeichnete Eingriffe bedeuten, dass auch die "
"zugehörigen Kompensationen automatisch entzeichnet worden sind."
#: templates/email/sharing/shared_access_given.html:4
msgid "Access shared"
msgstr "Zugriff freigegeben"
#: templates/email/sharing/shared_access_given.html:10
msgid "the following dataset has just been shared with you"
msgstr "der folgende Datensatz wurde soeben für Sie freigegeben "
#: templates/email/sharing/shared_access_given.html:14
msgid "This means you can now edit this dataset."
msgstr "Das bedeutet, dass Sie diesen Datensatz nun auch bearbeiten können."
#: templates/email/sharing/shared_access_given.html:15
msgid ""
"The shared dataset appears now by default on your overview for this dataset "
"type."
msgstr ""
"Der freigegebene Datensatz ist nun standardmäßig in Ihrer Übersicht für den "
"Datensatztyp im KSP gelistet."
#: templates/email/sharing/shared_access_given.html:25
msgid ""
"Please note: Shared access on an intervention means you automatically have "
"editing access to related compensations."
msgstr ""
"Bitte beachten Sie: Freigegebener Zugriff auf einen Eingriff bedeutet, dass "
"Sie automatisch auch Zugriff auf die zugehörigen Kompensationen erhalten "
"haben."
#: templates/email/sharing/shared_access_removed.html:4
msgid "Shared access removed"
msgstr "Freigegebener Zugriff entzogen"
#: templates/email/sharing/shared_access_removed.html:10
msgid ""
"your shared access, including editing, has been revoked for the dataset "
msgstr ""
"Ihnen wurde soeben der bearbeitende Zugriff auf den folgenden Datensatz "
"entzogen: "
#: templates/email/sharing/shared_access_removed.html:14
msgid "However, you are still able to view the dataset content."
msgstr "Sie können den Datensatz aber immer noch im KSP einsehen."
#: templates/email/sharing/shared_access_removed.html:15
msgid ""
"Please use the provided search filter on the dataset`s overview pages to "
"find them."
msgstr ""
"Nutzen Sie hierzu einfach die entsprechenden Suchfilter auf den "
"Übersichtsseiten"
#: templates/email/signature.html:6
msgid "Please do not reply on this mail."
msgstr "Bitte antworten Sie nicht auf diese Mail."
#: templates/email/signature.html:8
msgid "If needed, please contact "
msgstr "Bei Rückfragen, wenden Sie sich bitte an "
#: templates/footer.html:6
msgid "Help"
msgstr "Hilfe"
@ -2104,35 +1875,35 @@ msgstr "Abbrechen"
msgid "Fields with * are required."
msgstr "* sind Pflichtfelder."
#: templates/generic_index.html:39
#: templates/generic_index.html:28
msgid "New entry"
msgstr "Neuer Eintrag"
#: templates/generic_index.html:41
#: templates/generic_index.html:30
msgid "New"
msgstr "Neu"
#: templates/generic_index.html:56
#: templates/generic_index.html:45
msgid "Search for keywords"
msgstr "Nach Schlagwörtern suchen"
#: templates/generic_index.html:56
#: templates/generic_index.html:45
msgid "Search"
msgstr "Suchen"
#: templates/generic_index.html:57
#: templates/generic_index.html:46
msgid "Start search"
msgstr "Starte Suche"
#: templates/generic_index.html:69
#: templates/generic_index.html:58
msgid "Results per page"
msgstr "Treffer pro Seite"
#: templates/generic_index.html:93 templates/generic_index.html:118
#: templates/generic_index.html:82 templates/generic_index.html:88
msgid "Filter"
msgstr ""
#: templates/generic_index.html:120
#: templates/generic_index.html:90
msgid "Apply filter"
msgstr "Filter anwenden"
@ -2213,31 +1984,31 @@ msgstr "Wann wollen Sie per E-Mail benachrichtigt werden?"
msgid "Edit notifications"
msgstr "Benachrichtigungen bearbeiten"
#: user/forms.py:72 user/templates/user/index.html:9
#: user/forms.py:76 user/templates/user/index.html:9
msgid "Username"
msgstr "Nutzername"
#: user/forms.py:83
#: user/forms.py:87
msgid "Person name"
msgstr "Name"
#: user/forms.py:94 user/templates/user/index.html:17
#: user/forms.py:98 user/templates/user/index.html:17
msgid "E-Mail"
msgstr ""
#: user/forms.py:108
#: user/forms.py:112
msgid "User contact data"
msgstr "Kontaktdaten"
#: user/models/user_action.py:20
#: user/models/user_action.py:21
msgid "Unrecorded"
msgstr "Entzeichnet"
#: user/models/user_action.py:22
#: user/models/user_action.py:23
msgid "Edited"
msgstr "Bearbeitet"
#: user/models/user_action.py:23
#: user/models/user_action.py:24
msgid "Deleted"
msgstr "Gelöscht"
@ -2282,7 +2053,7 @@ msgstr "Benachrichtigungseinstellungen ändern"
msgid "Notification settings"
msgstr "Benachrichtigungen"
#: user/views.py:52
#: user/views.py:56
msgid "Notifications edited"
msgstr "Benachrichtigungen bearbeitet"
@ -3789,18 +3560,6 @@ msgstr ""
msgid "Unable to connect to qpid with SASL mechanism %s"
msgstr ""
#~ msgid "On registered data edited"
#~ msgstr "Wenn meine freigegebenen Daten bearbeitet wurden"
#~ msgid "Not recorded"
#~ msgstr "Noch nicht verzeichnet"
#~ msgid "On new related data"
#~ msgstr "Wenn neue Daten für mich angelegt werden"
#~ msgid "On disabled share link"
#~ msgstr "Wenn ein Freigabelink deaktiviert wird"
#~ msgid "Deduct"
#~ msgstr "Abbuchen"

View File

@ -1,13 +0,0 @@
{% extends 'public_base.html' %}
{% load i18n fontawesome_5 %}
{% block body %}
<div class="jumbotron">
<h1 class="display-4">{% fa5_icon 'question-circle' %} 404</h1>
<h1 class="display-4">{% trans 'Not found' %}</h1>
<hr>
<p class="lead">
{% trans 'The requested data does not exist.' %}
</p>
</div>
{% endblock %}

View File

@ -1,13 +0,0 @@
{% extends 'public_base.html' %}
{% load i18n fontawesome_5 %}
{% block body %}
<div class="jumbotron">
<h1 class="display-4">{% fa5_icon 'fire-extinguisher' %} {% fa5_icon 'fire-alt' %} 500</h1>
<h1 class="display-4">{% trans 'Server Error' %}</h1>
<hr>
<p class="lead">
{% trans 'Something happened. We are working on it!' %}
</p>
</div>
{% endblock %}

View File

@ -1,26 +0,0 @@
{% load i18n %}
<div>
<h2>{% trans 'Shared data checked' %}</h2>
<h4>{{obj_identifier}}</h4>
<hr>
<article>
{% trans 'Hello ' %} {{user.username}},
<br>
{% trans 'the following dataset has just been checked' %}
<br>
<strong>'{{obj_identifier}}'</strong>
<br>
{% trans 'This means, the responsible registration office just confirmed the correctness of this dataset.' %}
<br>
<br>
{% trans 'Best regards' %}
<br>
KSP
<br>
<br>
<br>
{% include 'email/signature.html' %}
</article>
</div>

View File

@ -1,26 +0,0 @@
{% load i18n %}
<div>
<h2>{% trans 'Shared data deleted' %}</h2>
<h4>{{obj_identifier}}</h4>
<hr>
<article>
{% trans 'Hello ' %} {{user.username}},
<br>
{% trans 'the following dataset has just been deleted' %}
<br>
<strong>'{{obj_identifier}}'</strong>
<br>
{% trans 'If this should not have been happened, please contact us. See the signature for details.' %}
<br>
<br>
{% trans 'Best regards' %}
<br>
KSP
<br>
<br>
<br>
{% include 'email/signature.html' %}
</article>
</div>

View File

@ -1,31 +0,0 @@
{% load i18n %}
<div>
<h2>{% trans 'Shared data recorded' %}</h2>
<h4>{{obj_identifier}}</h4>
<hr>
<article>
{% trans 'Hello ' %} {{user.username}},
<br>
{% trans 'the following dataset has just been recorded' %}
<br>
<strong>'{{obj_identifier}}'</strong>
<br>
{% trans 'This means the data is now publicly available, e.g. in LANIS' %}
<br>
<br>
{% trans 'Best regards' %}
<br>
KSP
<br>
<br>
<br>
<small>
{% trans 'Please note: Recorded intervention means the compensations are recorded as well.' %}
</small>
<br>
<br>
{% include 'email/signature.html' %}
</article>
</div>

View File

@ -1,31 +0,0 @@
{% load i18n %}
<div>
<h2>{% trans 'Shared data unrecorded' %}</h2>
<h4>{{obj_identifier}}</h4>
<hr>
<article>
{% trans 'Hello ' %} {{user.username}},
<br>
{% trans 'the following dataset has just been unrecorded' %}
<br>
<strong>'{{obj_identifier}}'</strong>
<br>
{% trans 'This means the data is no longer publicly available.' %}
<br>
<br>
{% trans 'Best regards' %}
<br>
KSP
<br>
<br>
<br>
<small>
{% trans 'Please note: Unrecorded intervention means the compensations are unrecorded as well.' %}
</small>
<br>
<br>
{% include 'email/signature.html' %}
</article>
</div>

View File

@ -1,32 +0,0 @@
{% load i18n %}
<div>
<h2>{% trans 'Access shared' %}</h2>
<h4>{{obj_identifier}}</h4>
<hr>
<article>
{% trans 'Hello ' %} {{user.username}},
<br>
{% trans 'the following dataset has just been shared with you' %}
<br>
<strong>'{{obj_identifier}}'</strong>
<br>
{% trans 'This means you can now edit this dataset.' %}
{% trans 'The shared dataset appears now by default on your overview for this dataset type.' %}
<br>
<br>
{% trans 'Best regards' %}
<br>
KSP
<br>
<br>
<br>
<small>
{% trans 'Please note: Shared access on an intervention means you automatically have editing access to related compensations.' %}
</small>
<br>
<br>
{% include 'email/signature.html' %}
</article>
</div>

View File

@ -1,27 +0,0 @@
{% load i18n %}
<div>
<h2>{% trans 'Shared access removed' %}</h2>
<h4>{{obj_identifier}}</h4>
<hr>
<article>
{% trans 'Hello ' %} {{user.username}},
<br>
{% trans 'your shared access, including editing, has been revoked for the dataset ' %}
<br>
<strong>'{{obj_identifier}}'</strong>
<br>
{% trans 'However, you are still able to view the dataset content.' %}
{% trans 'Please use the provided search filter on the dataset`s overview pages to find them.' %}
<br>
<br>
{% trans 'Best regards' %}
<br>
KSP
<br>
<br>
<br>
{% include 'email/signature.html' %}
</article>
</div>

View File

@ -1,10 +0,0 @@
{% load i18n %}
<div>
<hr>
<small>
{% trans 'Please do not reply on this mail.' %}
<br>
{% trans 'If needed, please contact ' %} <a href="mailto:{{EMAIL_REPLY_TO}}">{{EMAIL_REPLY_TO}}</a>.
</small>
</div>

View File

@ -1,5 +0,0 @@
{% for field in form %}
<div class="form-check form-check-inline">
{{field}} <label class="form-check-label" for="id_{{field.name}}">{{field.label}}</label>
</div>
{% endfor %}

View File

@ -1,10 +0,0 @@
<div class="form-row align-items-center">
{% for field in form %}
{% if not field.is_hidden %}
<div class="col-auto">
{{field}}
</div>
{% else %}
{% endif %}
{% endfor %}
</div>

View File

@ -9,7 +9,7 @@
<a href="{% url 'home' %}">{% trans 'Impressum' %}</a>
</span>
<span class="col-sm-auto footer-link">
<a href="mailto:{{CONTACT_MAIL}}">{% trans 'Contact' %}</a>
<a href="{% url 'home' %}">{% trans 'Contact' %}</a>
</span>
</div>
</div>

View File

@ -3,16 +3,6 @@
{% load django_tables2 %}
{% load i18n static fontawesome_5 %}
{% block head %}
{% comment %}
dal documentation (django-autocomplete-light) states using form.media for adding needed scripts.
This does not work properly with modal forms, as the scripts are not loaded properly inside the modal.
Therefore the script linkages from form.media have been extracted and put inside dal/scripts.html to ensure
these scripts are loaded when needed.
{% endcomment %}
{% include 'dal/scripts.html' %}
{% endblock %}
{% block body %}
<div class="col-md">
{% if table.title %}
@ -51,7 +41,7 @@
<div class="row my-1">
<div class="col-sm-12 col-md-8 col-lg-6">
<div class="input-group">
<input id="id_{{table.filter.query_filter.filters.q.field_name}}" name="{{table.filter.query_filter.filters.q.field_name}}" type="text" class="form-control" aria-label="{% trans 'Search for keywords' %}" placeholder="{% trans 'Search' %}" value="{{ request.GET.q }}">
<input id="id_{{table.filter.filters.q.field_name}}" name="{{table.filter.filters.q.field_name}}" type="text" class="form-control" aria-label="{% trans 'Search for keywords' %}" placeholder="{% trans 'Search' %}" value="{{ request.GET.q }}">
<div class="input-group-append" title="{% trans 'Start search' %}">
<button type="submit" class="btn btn-default input-group-text">
<span class="">
@ -92,32 +82,11 @@
</div>
<div id="filter" class="collapse" aria-labelledby="filterHeader">
<div class="card-body">
<div class="">
<div class="">
{% with table.filter.selection_filter.form as form %}
{% include 'filter/query_filter.html' %}
{% endwith %}
</div>
<hr>
<div class="mt-3">
{% with table.filter.query_filter.form as form %}
{% include 'filter/query_filter.html' %}
{% endwith %}
</div>
<hr>
<div class="mt-3">
{% with table.filter.checkbox_filter.form as form %}
{% include 'filter/checkbox_filter.html' %}
{% endwith %}
</div>
<hr>
<div class="mt-3">
<button class="btn btn-default" title="{% trans 'Filter' %}">
{% fa5_icon 'filter' %}
{% trans 'Apply filter' %}
</button>
</div>
</div>
{{ table.filter.form.as_p }}
<button class="btn btn-default" title="{% trans 'Filter' %}">
{% fa5_icon 'filter' %}
{% trans 'Apply filter' %}
</button>
</div>
</div>
</div>

View File

@ -41,6 +41,8 @@
</div>
<div class="dropdown-menu">
<a class="dropdown-item" href="{% url 'ema:index' %}" title="{% trans 'Payment funded compensations' %}">{% fa5_icon 'euro-sign' %} {% trans 'EMA' %}</a>
<a class="dropdown-item" href="{% url 'home' %}">{% fa5_icon 'file-import' %} {% trans 'Import...' %}</a>
<a class="dropdown-item" href="{% url 'home' %}">{% fa5_icon 'file-export' %} {% trans 'Export...' %}</a>
<a class="dropdown-item" href="{% url 'analysis:reports' %}">{% fa5_icon 'file-alt' %} {% trans 'Reports' %}</a>
</div>
</li>

View File

@ -1,6 +1,6 @@
from django.contrib import admin
from user.models import UserNotification, UserActionLogEntry, User
from user.models import UserNotification, KonovaUserExtension, UserActionLogEntry
class UserNotificationAdmin(admin.ModelAdmin):
@ -11,13 +11,9 @@ class UserNotificationAdmin(admin.ModelAdmin):
]
class UserAdmin(admin.ModelAdmin):
class KonovaUserExtensionAdmin(admin.ModelAdmin):
list_display = [
"id",
"username",
"first_name",
"last_name",
"email",
"user",
]
@ -31,5 +27,5 @@ class UserActionLogEntryAdmin(admin.ModelAdmin):
admin.site.register(UserNotification, UserNotificationAdmin)
admin.site.register(UserActionLogEntry, UserActionLogEntryAdmin)
admin.site.register(User, UserAdmin)
admin.site.register(KonovaUserExtension, KonovaUserExtensionAdmin)
admin.site.register(UserActionLogEntry, UserActionLogEntryAdmin)

View File

@ -9,8 +9,9 @@ from konova.enums import BaseEnum
class UserNotificationEnum(BaseEnum):
NOTIFY_ON_NEW_RELATED_DATA = "NOTIFY_ON_NEW_RELATED_DATA" # notifies in case new data has been added which is related to the user's organisation
NOTIFY_ON_SHARE_LINK_DISABLED = "NOTIFY_ON_SHARE_LINK_DISABLED" # notifies in case share link for data has been disabled
NOTIFY_ON_SHARED_ACCESS_REMOVED = "NOTIFY_ON_SHARED_ACCESS_REMOVED" # notifies in case shared access to data has been removed
NOTIFY_ON_SHARED_DATA_RECORDED = "NOTIFY_ON_SHARED_DATA_RECORDED" # notifies in case data has been "verzeichnet"
NOTIFY_ON_SHARED_DATA_DELETED = "NOTIFY_ON_SHARED_DATA_DELETED" # notifies in case data has been deleted
NOTIFY_ON_SHARED_DATA_CHECKED = "NOTIFY_ON_SHARED_DATA_CHECKED" # notifies in case shared data has been checked
NOTIFY_ON_SHARED_ACCESS_GAINED = "NOTIFY_ON_SHARED_ACCESS_GAINED" # notifies in case new access has been gained
NOTIFY_ON_REGISTERED_DATA_EDITED = "NOTIFY_ON_REGISTERED_DATA_EDITED" # notifies in case registered ("verzeichnet") data has been edited

View File

@ -8,10 +8,10 @@ Created on: 08.07.21
from django import forms
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from user.models import User
from django.contrib.auth.models import User
from konova.forms import BaseForm, BaseModalForm
from user.models import UserNotification
from user.models import UserNotification, KonovaUserExtension
class UserNotificationForm(BaseForm):
@ -50,7 +50,11 @@ class UserNotificationForm(BaseForm):
)
self.fields["notifications"].choices = choices
users_current_notifications = self.user.notifications.all()
# Set currently selected notifications as initial
self.konova_extension = KonovaUserExtension.objects.get_or_create(
user=user
)[0]
users_current_notifications = self.konova_extension.notifications.all()
users_current_notifications = [str(n.id) for n in users_current_notifications]
self.fields["notifications"].initial = users_current_notifications
@ -64,7 +68,7 @@ class UserNotificationForm(BaseForm):
notifications = UserNotification.objects.filter(
id__in=selected_notification_ids,
)
self.user.notifications.set(notifications)
self.konova_extension.notifications.set(notifications)
class UserContactForm(BaseModalForm):

View File

@ -6,5 +6,5 @@ Created on: 15.11.21
"""
from .user_action import *
from .user import *
from .konova_user import *
from .notification import *

View File

@ -0,0 +1,19 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 15.11.21
"""
from django.contrib.auth.models import User
from django.db import models
class KonovaUserExtension(models.Model):
""" Extension model for additional ksp features
Extends the default user model for some extras
"""
user = models.OneToOneField(User, on_delete=models.CASCADE)
notifications = models.ManyToManyField("user.UserNotification", related_name="+")

View File

@ -1,106 +0,0 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 15.11.21
"""
from django.contrib.auth.models import AbstractUser
from django.db import models
from konova.utils.mailer import Mailer
from user.enums import UserNotificationEnum
class User(AbstractUser):
notifications = models.ManyToManyField("user.UserNotification", related_name="+", blank=True)
def is_notification_setting_set(self, notification_enum: UserNotificationEnum):
return self.notifications.filter(
id=notification_enum.value
).exists()
def send_mail_shared_access_removed(self, obj_identifier):
""" Sends a mail to the user in case of removed shared access
Args:
obj_identifier ():
Returns:
"""
notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_ACCESS_REMOVED)
if notification_set:
mailer = Mailer()
mailer.send_mail_shared_access_removed(obj_identifier, self)
def send_mail_shared_access_given(self, obj_identifier):
""" Sends a mail to the user in case of given shared access
Args:
obj_identifier ():
Returns:
"""
notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_ACCESS_GAINED)
if notification_set:
mailer = Mailer()
mailer.send_mail_shared_access_given(obj_identifier, self)
def send_mail_shared_data_recorded(self, obj_identifier):
""" Sends a mail to the user in case of shared data has been recorded
Args:
obj_identifier ():
Returns:
"""
notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_DATA_RECORDED)
if notification_set:
mailer = Mailer()
mailer.send_mail_shared_data_recorded(obj_identifier, self)
def send_mail_shared_data_unrecorded(self, obj_identifier):
""" Sends a mail to the user in case of shared data has been unrecorded
Args:
obj_identifier ():
Returns:
"""
notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_DATA_RECORDED)
if notification_set:
mailer = Mailer()
mailer.send_mail_shared_data_unrecorded(obj_identifier, self)
def send_mail_shared_data_deleted(self, obj_identifier):
""" Sends a mail to the user in case of shared data has been deleted
Args:
obj_identifier ():
Returns:
"""
notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_DATA_DELETED)
if notification_set:
mailer = Mailer()
mailer.send_mail_shared_data_deleted(obj_identifier, self)
def send_mail_shared_data_checked(self, obj_identifier):
""" Sends a mail to the user in case of shared data has been deleted
Args:
obj_identifier ():
Returns:
"""
notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_DATA_CHECKED)
if notification_set:
mailer = Mailer()
mailer.send_mail_shared_data_checked(obj_identifier, self)

View File

@ -7,6 +7,7 @@ Created on: 15.11.21
"""
import uuid
from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import gettext_lazy as _
@ -33,7 +34,7 @@ class UserActionLogEntry(models.Model):
primary_key=True,
default=uuid.uuid4,
)
user = models.ForeignKey("user.User", related_name='+', on_delete=models.CASCADE, help_text="Performing user")
user = models.ForeignKey(User, related_name='+', on_delete=models.CASCADE, help_text="Performing user")
timestamp = models.DateTimeField(auto_now_add=True, help_text="Timestamp of performed action")
action = models.CharField(
max_length=255,
@ -49,6 +50,9 @@ class UserActionLogEntry(models.Model):
"-timestamp",
)
def __str__(self):
return "{} | {} | {}".format(self.user.username, self.timestamp, self.action)
@property
def action_humanize(self):
""" Returns humanized version of enum
@ -65,7 +69,7 @@ class UserActionLogEntry(models.Model):
return None
@classmethod
def get_created_action(cls, user, comment: str = None):
def get_created_action(cls, user: User, comment: str = None):
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.CREATED,
@ -74,7 +78,7 @@ class UserActionLogEntry(models.Model):
return action
@classmethod
def get_edited_action(cls, user, comment: str = None):
def get_edited_action(cls, user: User, comment: str = None):
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.EDITED,
@ -83,7 +87,7 @@ class UserActionLogEntry(models.Model):
return action
@classmethod
def get_deleted_action(cls, user, comment: str = None):
def get_deleted_action(cls, user: User, comment: str = None):
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.DELETED,
@ -92,7 +96,7 @@ class UserActionLogEntry(models.Model):
return action
@classmethod
def get_checked_action(cls, user, comment: str = None):
def get_checked_action(cls, user: User, comment: str = None):
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.CHECKED,
@ -101,7 +105,7 @@ class UserActionLogEntry(models.Model):
return action
@classmethod
def get_recorded_action(cls, user, comment: str = None):
def get_recorded_action(cls, user: User, comment: str = None):
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.RECORDED,
@ -110,7 +114,7 @@ class UserActionLogEntry(models.Model):
return action
@classmethod
def get_unrecorded_action(cls, user, comment: str = None):
def get_unrecorded_action(cls, user: User, comment: str = None):
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.UNRECORDED,

View File

@ -1,6 +1,6 @@
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from user.models import User
from django.contrib.auth.models import User
from django.http import HttpRequest
from django.shortcuts import render, redirect, get_object_or_404
from django.utils.translation import gettext_lazy as _
@ -8,6 +8,7 @@ from django.utils.translation import gettext_lazy as _
from konova.contexts import BaseContext
from konova.decorators import any_group_check
from user.forms import UserNotificationForm, UserContactForm
from user.models import KonovaUserExtension
@login_required
@ -42,6 +43,9 @@ def notifications_view(request: HttpRequest):
"""
template = "user/notifications.html"
user = request.user
konova_ext = KonovaUserExtension.objects.get_or_create(
user=user
)[0]
form = UserNotificationForm(user=user, data=request.POST or None)
if request.method == "POST":
@ -61,6 +65,7 @@ def notifications_view(request: HttpRequest):
context = {
"user": user,
"form": form,
"konova_ext": konova_ext,
}
context = BaseContext(request, context).context
return render(request, template, context)