Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 210f3fcafa | |||
| e7d67560f2 | |||
| b5e991fb95 | |||
| d3a555d406 | |||
| 9a374f50de | |||
| ce63dd30bc | |||
| e5db7f6b13 | |||
| 442f3ceb37 | |||
| cd2949fc03 | |||
| 7bcd32fd7a | |||
| 97f1882698 | |||
| 55cc8eb1f3 | |||
| d6cabd5f6c | |||
| 63a824f9d9 | |||
| a12c2fb57e | |||
| 23bc79ee3b | |||
| 07bac26a58 | |||
| d01816cf71 | |||
| f543dfc1cb | |||
| 62fc019127 | |||
| c01518b675 | |||
| f57306eb72 | |||
| c2b12649b0 | |||
| 6fe67a8fbf | |||
| b38a266bea | |||
| 15f86e866b | |||
| c85b136f0a | |||
| faf8aed777 | |||
| 94c498866f | |||
| 616965c890 | |||
| e39c7eb51f | |||
| 19bd408fbd | |||
| 7bfe6a37f8 | |||
| 9b63307f01 | |||
| 123a470006 | |||
| 5a0c5285e7 | |||
| 3a01eaff92 | |||
| 2af91aa178 | |||
| 53d0af89ac | |||
| 7b5c1f0d97 | |||
| ef076c0b3b | |||
| 72a5075f3b | |||
| d677ac6b5a | |||
| 9149e4cbd3 | |||
| 1c24cbea26 | |||
|
|
bc9cc09372 | ||
| 24518465f3 | |||
| 457548da4d | |||
| fa89bbba99 | |||
| 78eb711057 | |||
| 6ff67d12c9 | |||
| 3c1cbcd0bd | |||
| 416ad8478c | |||
| 6b28c4ec15 | |||
| 46a2a4ff46 | |||
| 90e5cf5b36 | |||
| 50f46e319c | |||
| e2ea087c4e | |||
| a6e43b044b | |||
| be0d261e81 | |||
| 62e1b046c3 | |||
| 669a12410f | |||
| dd77e6c16e | |||
| 33774ce557 | |||
| dc3dc99b3d | |||
| 315f9de958 | |||
| 0726c15086 | |||
| 2492a8abe8 | |||
| dbc5cba5d7 | |||
| c8948ddaea | |||
| 5039da28aa | |||
| 4567339570 | |||
| 768849e646 | |||
| ebf10645fc | |||
| df241747cf | |||
| 94e9035e10 |
@@ -24,6 +24,7 @@ DEFAULT_FROM_EMAIL=service@ksp.de
|
||||
|
||||
# Proxy
|
||||
PROXY=CHANGE_ME
|
||||
MAP_PROXY_HOST_WHITELIST=CHANGE_ME_1,CHANGE_ME_2
|
||||
GEOPORTAL_RLP_USER=CHANGE_ME
|
||||
GEOPORTAL_RLP_PASSWORD=CHANGE_ME
|
||||
|
||||
@@ -37,6 +38,7 @@ SSO_SERVER_BASE_URL=https://login.naturschutz.rlp.de
|
||||
OAUTH_CODE_VERIFIER=CHANGE_ME
|
||||
OAUTH_CLIENT_ID=CHANGE_ME
|
||||
OAUTH_CLIENT_SECRET=CHANGE_ME
|
||||
PROPAGATION_SECRET=CHANGE_ME
|
||||
|
||||
# RabbitMQ
|
||||
## For connections to EGON
|
||||
|
||||
@@ -51,7 +51,7 @@ class APIUserToken(models.Model):
|
||||
if token_obj.valid_until is not None and token_obj.valid_until < _today:
|
||||
raise PermissionError("Token validity expired")
|
||||
except ObjectDoesNotExist:
|
||||
raise PermissionError("Credentials invalid")
|
||||
raise PermissionError("Token unknown")
|
||||
return token_obj.user
|
||||
|
||||
|
||||
@@ -155,3 +155,25 @@ class OAuthToken(UuidModel):
|
||||
|
||||
return user
|
||||
|
||||
def revoke(self) -> int:
|
||||
""" Revokes the OAuth2 token of the user
|
||||
|
||||
(/o/revoke_token/ indeed removes the corresponding access token on provider side and invalidates the
|
||||
submitted refresh token in one step)
|
||||
|
||||
Returns:
|
||||
revocation_status_code (int): HTTP status code for revocation of refresh_token
|
||||
"""
|
||||
revoke_url = f"{SSO_SERVER_BASE}o/revoke_token/"
|
||||
token = self.refresh_token
|
||||
revocation_status_code = requests.post(
|
||||
revoke_url,
|
||||
data={
|
||||
'token': token,
|
||||
'token_type_hint': "refresh_token",
|
||||
},
|
||||
auth=(OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET),
|
||||
).status_code
|
||||
|
||||
return revocation_status_code
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from django.contrib.gis import geos
|
||||
from django.urls import reverse
|
||||
|
||||
from api.tests.v1.share.test_api_sharing import BaseAPIV1TestCase
|
||||
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
|
||||
from konova.models import Geometry
|
||||
|
||||
|
||||
class APIV1UpdateTestCase(BaseAPIV1TestCase):
|
||||
@@ -64,7 +64,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
|
||||
|
||||
put_props = put_body["properties"]
|
||||
put_geom = geos.fromstr(json.dumps(put_body))
|
||||
put_geom.transform(DEFAULT_SRID_RLP)
|
||||
put_geom = Geometry.cast_to_rlp_srid(put_geom)
|
||||
self.assertEqual(put_geom, self.intervention.geometry.geom)
|
||||
self.assertEqual(put_props["title"], self.intervention.title)
|
||||
self.assertNotEqual(modified_on, self.intervention.modified)
|
||||
@@ -94,7 +94,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
|
||||
|
||||
put_props = put_body["properties"]
|
||||
put_geom = geos.fromstr(json.dumps(put_body))
|
||||
put_geom.transform(DEFAULT_SRID_RLP)
|
||||
put_geom = Geometry.cast_to_rlp_srid(put_geom)
|
||||
self.assertEqual(put_geom, self.compensation.geometry.geom)
|
||||
self.assertEqual(put_props["title"], self.compensation.title)
|
||||
self.assertNotEqual(modified_on, self.compensation.modified)
|
||||
@@ -124,7 +124,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
|
||||
|
||||
put_props = put_body["properties"]
|
||||
put_geom = geos.fromstr(json.dumps(put_body))
|
||||
put_geom.transform(DEFAULT_SRID_RLP)
|
||||
put_geom = Geometry.cast_to_rlp_srid(put_geom)
|
||||
self.assertEqual(put_geom, self.eco_account.geometry.geom)
|
||||
self.assertEqual(put_props["title"], self.eco_account.title)
|
||||
self.assertNotEqual(modified_on, self.eco_account.modified)
|
||||
@@ -156,7 +156,7 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
|
||||
|
||||
put_props = put_body["properties"]
|
||||
put_geom = geos.fromstr(json.dumps(put_body))
|
||||
put_geom.transform(DEFAULT_SRID_RLP)
|
||||
put_geom = Geometry.cast_to_rlp_srid(put_geom)
|
||||
self.assertEqual(put_geom, self.ema.geometry.geom)
|
||||
self.assertEqual(put_props["title"], self.ema.title)
|
||||
self.assertNotEqual(modified_on, self.ema.modified)
|
||||
|
||||
@@ -13,7 +13,7 @@ from django.contrib.gis.geos import GEOSGeometry
|
||||
from django.core.paginator import Paginator
|
||||
from django.db.models import Q
|
||||
|
||||
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
|
||||
from konova.models import Geometry
|
||||
from konova.utils.message_templates import DATA_UNSHARED
|
||||
|
||||
|
||||
@@ -145,8 +145,8 @@ class AbstractModelAPISerializer:
|
||||
if isinstance(geojson, dict):
|
||||
geojson = json.dumps(geojson)
|
||||
geometry = geos.fromstr(geojson)
|
||||
if geometry.srid != DEFAULT_SRID_RLP:
|
||||
geometry.transform(DEFAULT_SRID_RLP)
|
||||
geometry = Geometry.cast_to_rlp_srid(geometry)
|
||||
geometry = Geometry.cast_to_multipolygon(geometry)
|
||||
return geometry
|
||||
|
||||
def _get_obj_from_db(self, id, user):
|
||||
|
||||
@@ -16,7 +16,8 @@ from api.utils.serializer.serializer import AbstractModelAPISerializer
|
||||
from codelist.models import KonovaCode
|
||||
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID, CODELIST_PROCESS_TYPE_ID, \
|
||||
CODELIST_LAW_ID, CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID, \
|
||||
CODELIST_COMPENSATION_ACTION_DETAIL_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID, CODELIST_HANDLER_ID
|
||||
CODELIST_COMPENSATION_ACTION_DETAIL_ID, CODELIST_HANDLER_ID, \
|
||||
CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID
|
||||
from compensation.models import CompensationAction, UnitChoices, CompensationState
|
||||
from intervention.models import Responsibility, Legal, Handler
|
||||
from konova.models import Deadline, DeadlineType
|
||||
@@ -347,7 +348,7 @@ class AbstractCompensationAPISerializerV1Mixin:
|
||||
try:
|
||||
biotope_type = entry["biotope"]
|
||||
biotope_details = [
|
||||
self._konova_code_from_json(e, CODELIST_BIOTOPES_EXTRA_CODES_ID) for e in entry["biotope_details"]
|
||||
self._konova_code_from_json(e, CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID) for e in entry["biotope_details"]
|
||||
]
|
||||
surface = float(entry["surface"])
|
||||
except KeyError:
|
||||
|
||||
@@ -50,13 +50,18 @@ class AbstractAPIView(View):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
try:
|
||||
# Fetch the proper user from the given request header token
|
||||
ksp_token = request.headers.get(KSP_TOKEN_HEADER_IDENTIFIER, None)
|
||||
token = request.headers.get(KSP_TOKEN_HEADER_IDENTIFIER, None)
|
||||
ksp_user = request.headers.get(KSP_USER_HEADER_IDENTIFIER, None)
|
||||
token_user = APIUserToken.get_user_from_token(ksp_token)
|
||||
|
||||
if ksp_user != token_user.username:
|
||||
if not token and not ksp_user:
|
||||
bearer_token = request.headers.get("authorization", None)
|
||||
if not bearer_token:
|
||||
raise PermissionError("No token provided")
|
||||
token = bearer_token.split(" ")[1]
|
||||
|
||||
token_user = APIUserToken.get_user_from_token(token)
|
||||
if ksp_user and ksp_user != token_user.username:
|
||||
raise PermissionError(f"Invalid token for {ksp_user}")
|
||||
else:
|
||||
self.user = token_user
|
||||
|
||||
request.user = self.user
|
||||
|
||||
@@ -9,7 +9,8 @@ import collections
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID
|
||||
from codelist.settings import CODELIST_BIOTOPES_ID, \
|
||||
CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID
|
||||
from codelist.autocomplete.base import KonovaCodeAutocomplete
|
||||
from konova.utils.message_templates import UNGROUPED
|
||||
|
||||
@@ -84,11 +85,11 @@ class BiotopeExtraCodeAutocomplete(KonovaCodeAutocomplete):
|
||||
Due to limitations of the django dal package, we need to subclass for each code list
|
||||
"""
|
||||
group_by_related = "parent"
|
||||
related_field_name = "long_name"
|
||||
related_field_name = "short_name"
|
||||
paginate_by = 200
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.c = CODELIST_BIOTOPES_EXTRA_CODES_ID
|
||||
self.c = CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def order_by(self, qs):
|
||||
@@ -103,8 +104,11 @@ class BiotopeExtraCodeAutocomplete(KonovaCodeAutocomplete):
|
||||
qs (QuerySet): The ordered queryset
|
||||
"""
|
||||
return qs.order_by(
|
||||
"long_name",
|
||||
"short_name",
|
||||
)
|
||||
|
||||
def get_result_label(self, result):
|
||||
return f"{result.long_name} ({result.short_name})"
|
||||
|
||||
def get_selected_result_label(self, result):
|
||||
return f"{result.parent.short_name} > {result.long_name} ({result.short_name})"
|
||||
@@ -13,7 +13,7 @@ from codelist.settings import CODELIST_INTERVENTION_HANDLER_ID, CODELIST_CONSERV
|
||||
CODELIST_REGISTRATION_OFFICE_ID, CODELIST_BIOTOPES_ID, CODELIST_LAW_ID, CODELIST_HANDLER_ID, \
|
||||
CODELIST_COMPENSATION_ACTION_ID, CODELIST_COMPENSATION_ACTION_CLASS_ID, CODELIST_COMPENSATION_ADDITIONAL_TYPE_ID, \
|
||||
CODELIST_BASE_URL, CODELIST_PROCESS_TYPE_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID, \
|
||||
CODELIST_COMPENSATION_ACTION_DETAIL_ID
|
||||
CODELIST_COMPENSATION_ACTION_DETAIL_ID, CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID
|
||||
from konova.management.commands.setup import BaseKonovaCommand
|
||||
from konova.settings import PROXIES
|
||||
|
||||
@@ -34,6 +34,7 @@ class Command(BaseKonovaCommand):
|
||||
CODELIST_REGISTRATION_OFFICE_ID,
|
||||
CODELIST_BIOTOPES_ID,
|
||||
CODELIST_BIOTOPES_EXTRA_CODES_ID,
|
||||
CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID,
|
||||
CODELIST_LAW_ID,
|
||||
CODELIST_HANDLER_ID,
|
||||
CODELIST_COMPENSATION_ACTION_ID,
|
||||
@@ -55,7 +56,7 @@ class Command(BaseKonovaCommand):
|
||||
content = result.content.decode("utf-8")
|
||||
root = etree.fromstring(content)
|
||||
items = root.findall("item")
|
||||
self._write_warning("Found {} codes. Process now...".format(len(items)))
|
||||
self._write_warning(" Found {} codes. Process now...".format(len(items)))
|
||||
|
||||
code_list = KonovaCodeList.objects.get_or_create(
|
||||
id=list_id,
|
||||
@@ -81,8 +82,8 @@ class Command(BaseKonovaCommand):
|
||||
atom_id = element.find("atomid").text
|
||||
selectable = element.find("selectable").text.lower()
|
||||
selectable = bool_map.get(selectable, False)
|
||||
short_name = element.find("shortname").text
|
||||
long_name = element.find("longname").text
|
||||
short_name = element.find("shortname").text or ""
|
||||
long_name = element.find("longname").text or ""
|
||||
is_archived = bool_map.get((element.find("archive").text.lower()), False)
|
||||
|
||||
code = KonovaCode.objects.get_or_create(
|
||||
|
||||
60
codelist/migrations/0002_migrate_975_to_288.py
Normal file
60
codelist/migrations/0002_migrate_975_to_288.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# Generated by Django 5.0.7 on 2024-08-06 13:40
|
||||
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import migrations
|
||||
from django.db.models import Q
|
||||
|
||||
from codelist.settings import CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID
|
||||
|
||||
|
||||
def migrate_975_to_288(apps, schema_editor):
|
||||
KonovaCodeList = apps.get_model('codelist', 'KonovaCodeList')
|
||||
CompensationState = apps.get_model('compensation', 'CompensationState')
|
||||
|
||||
try:
|
||||
list_288 = KonovaCodeList.objects.get(
|
||||
id=CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID
|
||||
).codes.all()
|
||||
except ObjectDoesNotExist:
|
||||
raise AssertionError("KonovaCodeList 288 does not exist. Did you run 'update_codelist' before migrating?")
|
||||
|
||||
states_with_extra_code = CompensationState.objects.filter(
|
||||
~Q(biotope_type_details=None)
|
||||
)
|
||||
|
||||
print(f"... Found {states_with_extra_code.count()} biotope state entries")
|
||||
for state in states_with_extra_code:
|
||||
extra_codes_975 = state.biotope_type_details.filter(
|
||||
code_lists__in=[CODELIST_BIOTOPES_EXTRA_CODES_ID]
|
||||
)
|
||||
count_extra_codes_975 = extra_codes_975.count()
|
||||
if count_extra_codes_975 > 0:
|
||||
print(f" --> Found {count_extra_codes_975} codes from list 975 in biotope entry {state.id}")
|
||||
extra_codes_288 = []
|
||||
for extra_code_975 in extra_codes_975:
|
||||
atom_id = extra_code_975.atom_id
|
||||
codes_from_288 = list_288.filter(
|
||||
atom_id=atom_id,
|
||||
)
|
||||
extra_codes_288 += codes_from_288
|
||||
|
||||
state.biotope_type_details.set(extra_codes_288)
|
||||
print(" --> Migrated to list 288 for all biotope entries")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('codelist', '0001_initial'),
|
||||
('compensation', '0003_auto_20220202_0846'),
|
||||
]
|
||||
|
||||
# If migration of codelist is not necessary, this variable can shut down the logic whilst not disturbing the
|
||||
# migration history
|
||||
EXECUTE_CODELIST_MIGRATION = True
|
||||
|
||||
operations = []
|
||||
|
||||
if EXECUTE_CODELIST_MIGRATION:
|
||||
operations.append(migrations.RunPython(migrate_975_to_288))
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 5.0.8 on 2024-08-26 16:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('codelist', '0002_migrate_975_to_288'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='konovacode',
|
||||
name='long_name',
|
||||
field=models.CharField(blank=True, default="", max_length=1000),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='konovacode',
|
||||
name='short_name',
|
||||
field=models.CharField(blank=True, default="", help_text='Short version of long name', max_length=500),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -25,13 +25,11 @@ class KonovaCode(models.Model):
|
||||
)
|
||||
short_name = models.CharField(
|
||||
max_length=500,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Short version of long name",
|
||||
)
|
||||
long_name = models.CharField(
|
||||
max_length=1000,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="",
|
||||
)
|
||||
@@ -50,12 +48,28 @@ class KonovaCode(models.Model):
|
||||
|
||||
def __str__(self, with_parent: bool = True):
|
||||
ret_val = ""
|
||||
if self.parent and self.parent.long_name and with_parent:
|
||||
|
||||
long_name = self.long_name
|
||||
short_name = self.short_name
|
||||
|
||||
both_names_exist = long_name is not None and short_name is not None
|
||||
|
||||
if both_names_exist:
|
||||
if with_parent and self.parent:
|
||||
parent_short_name_exists = self.parent.short_name is not None
|
||||
parent_long_name_exists = self.parent.long_name is not None
|
||||
if parent_long_name_exists:
|
||||
ret_val += self.parent.long_name + " > "
|
||||
ret_val += self.long_name
|
||||
if self.short_name and self.short_name != self.long_name:
|
||||
# Only add short name, if we won't have stupid repition like 'thing a (thing a)' due to misused long-short names
|
||||
ret_val += f" ({self.short_name})"
|
||||
elif parent_short_name_exists:
|
||||
ret_val += self.parent.short_name + " > "
|
||||
|
||||
ret_val += long_name
|
||||
|
||||
if short_name and short_name != long_name:
|
||||
ret_val += f" ({short_name})"
|
||||
else:
|
||||
ret_val += str(long_name or short_name)
|
||||
|
||||
return ret_val
|
||||
|
||||
@property
|
||||
|
||||
@@ -15,7 +15,8 @@ CODELIST_CONSERVATION_OFFICE_ID = 907 # CLNaturschutzbehörden
|
||||
CODELIST_REGISTRATION_OFFICE_ID = 1053 # CLZulassungsbehörden
|
||||
CODELIST_BIOTOPES_ID = 654 # CL_Biotoptypen
|
||||
CODELIST_AFTER_STATE_BIOTOPES_ID = 974 # CL-KSP_ZielBiotoptypen - USAGE HAS BEEN DROPPED IN 2022 IN FAVOR OF 654
|
||||
CODELIST_BIOTOPES_EXTRA_CODES_ID = 975 # CLZusatzbezeichnung
|
||||
CODELIST_BIOTOPES_EXTRA_CODES_ID = 975 # CLZusatzbezeichnung - Subset of 288. Migration usage 975->288 in 08/2024
|
||||
CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID = 288 # CLBiotoptypZusatzcode
|
||||
CODELIST_LAW_ID = 1048 # CLVerfahrensrecht
|
||||
CODELIST_PROCESS_TYPE_ID = 44382 # CLVerfahrenstyp
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ from django.shortcuts import render
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from codelist.models import KonovaCode
|
||||
from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID
|
||||
from codelist.settings import CODELIST_BIOTOPES_ID, \
|
||||
CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID
|
||||
from intervention.inputs import CompensationStateTreeRadioSelect
|
||||
from konova.contexts import BaseContext
|
||||
from konova.forms.modals import RemoveModalForm, BaseModalForm
|
||||
@@ -43,7 +44,7 @@ class NewCompensationStateModalForm(BaseModalForm):
|
||||
queryset=KonovaCode.objects.filter(
|
||||
is_archived=False,
|
||||
is_leaf=True,
|
||||
code_lists__in=[CODELIST_BIOTOPES_EXTRA_CODES_ID],
|
||||
code_lists__in=[CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID],
|
||||
),
|
||||
widget=autocomplete.ModelSelect2Multiple(
|
||||
url="codelist:biotope-extra-type-autocomplete",
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.0.8 on 2024-08-26 16:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('codelist', '0003_alter_konovacode_long_name_and_more'),
|
||||
('compensation', '0015_alter_compensation_after_states_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='compensationstate',
|
||||
name='biotope_type_details',
|
||||
field=models.ManyToManyField(blank=True, limit_choices_to={'code_lists__in': [288], 'is_archived': False, 'is_selectable': True}, related_name='+', to='codelist.konovacode'),
|
||||
),
|
||||
]
|
||||
@@ -6,10 +6,10 @@ Created on: 16.11.21
|
||||
|
||||
"""
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
|
||||
from codelist.models import KonovaCode
|
||||
from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID
|
||||
from codelist.settings import CODELIST_BIOTOPES_ID, \
|
||||
CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID
|
||||
from compensation.managers import CompensationStateManager
|
||||
from konova.models import UuidModel
|
||||
|
||||
@@ -34,7 +34,7 @@ class CompensationState(UuidModel):
|
||||
KonovaCode,
|
||||
blank=True,
|
||||
limit_choices_to={
|
||||
"code_lists__in": [CODELIST_BIOTOPES_EXTRA_CODES_ID],
|
||||
"code_lists__in": [CODELIST_BIOTOPES_EXTRA_CODES_FULL_ID],
|
||||
"is_selectable": True,
|
||||
"is_archived": False,
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'compensation:new-action' obj.id %}" title="{% trans 'Add new action' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'seedling' %}
|
||||
@@ -34,7 +34,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Comment' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -52,7 +52,7 @@
|
||||
<hr>
|
||||
{% endfor %}
|
||||
{% for detail in action.action_type_details.all %}
|
||||
<span class="badge badge-pill rlp-r" title="{{detail}}">{{detail.long_name}}</span>
|
||||
<span class="badge badge-pill rlp-r" title="{{ detail.parent.long_name }} > {{detail}}">{{ detail.parent.long_name }} > {{detail.long_name}}</span>
|
||||
{% empty %}
|
||||
<span class="badge badge-pill rlp-r-outline" title="{% trans 'No action type details' %}">{% trans 'No action type details' %}</span>
|
||||
{% endfor %}
|
||||
@@ -64,7 +64,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'compensation:action-edit' obj.id action.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit action' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{% fa5_icon 'file-alt' %}
|
||||
</button>
|
||||
</a>
|
||||
{% if has_access %}
|
||||
{% if is_entry_shared %}
|
||||
<button class="btn btn-default btn-modal mr-2" title="{% trans 'Resubmission' %}" data-form-url="{% url 'compensation:resubmission-create' obj.id %}">
|
||||
{% fa5_icon 'bell' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'compensation:new-deadline' obj.id %}" title="{% trans 'Add new deadline' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'calendar-check' %}
|
||||
@@ -38,7 +38,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Comment' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -60,7 +60,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'compensation:deadline-edit' obj.id deadline.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit deadline' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'compensation:new-doc' obj.id %}" title="{% trans 'Add new document' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'file' %}
|
||||
@@ -33,7 +33,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Comment' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -59,7 +59,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'compensation:edit-doc' obj.id doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit document' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'compensation:new-state' obj.id %}" title="{% trans 'Add new state after' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'layer-group' %}
|
||||
@@ -35,7 +35,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Surface' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -51,14 +51,14 @@
|
||||
<span>{{ state.biotope_type.parent.long_name }} {% fa5_icon 'angle-right' %} {{ state.biotope_type.long_name }} ({{state.biotope_type.short_name}})</span>
|
||||
<br>
|
||||
{% for detail in state.biotope_type_details.all %}
|
||||
<span class="badge badge-pill rlp-r" title="{{detail}}">{{detail.long_name}}</span>
|
||||
<span class="badge badge-pill rlp-r" title="{{ detail.parent.short_name }} > {{detail}}">{{ detail.parent.short_name }} > {{ detail.long_name }}</span>
|
||||
{% empty %}
|
||||
<span class="badge badge-pill rlp-r-outline" title="{% trans 'No biotope type details' %}">{% trans 'No biotope type details' %}</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>{{ state.surface|floatformat:2 }} m²</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'compensation:state-edit' obj.id state.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit state' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'compensation:new-state' obj.id %}?before=true" title="{% trans 'Add new state before' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'layer-group' %}
|
||||
@@ -35,7 +35,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Surface' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -51,14 +51,14 @@
|
||||
<span>{{ state.biotope_type.parent.long_name }} {% fa5_icon 'angle-right' %} {{ state.biotope_type.long_name }} ({{state.biotope_type.short_name}})</span>
|
||||
<br>
|
||||
{% for detail in state.biotope_type_details.all %}
|
||||
<span class="badge badge-pill rlp-r" title="{{detail}}">{{detail.long_name}}</span>
|
||||
<span class="badge badge-pill rlp-r" title="{{ detail.parent.short_name }} > {{detail}}">{{ detail.parent.short_name }} > {{ detail.long_name }}</span>
|
||||
{% empty %}
|
||||
<span class="badge badge-pill rlp-r-outline" title="{% trans 'No biotope type details' %}">{% trans 'No biotope type details' %}</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>{{ state.surface|floatformat:2 }} m²</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'compensation:state-edit' obj.id state.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit state' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
{% include 'user/includes/team_data_modal_button.html' %}
|
||||
{% endfor %}
|
||||
<hr>
|
||||
{% if has_access %}
|
||||
{% if is_entry_shared %}
|
||||
{% for user in obj.intervention.shared_users %}
|
||||
{% include 'user/includes/contact_modal_button.html' %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'compensation:acc:new-action' obj.id %}" title="{% trans 'Add new action' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'seedling' %}
|
||||
@@ -33,7 +33,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Comment' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -51,7 +51,7 @@
|
||||
<hr>
|
||||
{% endfor %}
|
||||
{% for detail in action.action_type_details.all %}
|
||||
<span class="badge badge-pill rlp-r" title="{{detail}}">{{detail.long_name}}</span>
|
||||
<span class="badge badge-pill rlp-r" title="{{ detail.parent.long_name }} > {{detail}}">{{ detail.parent.long_name }} > {{detail.long_name}}</span>
|
||||
{% empty %}
|
||||
<span class="badge badge-pill rlp-r-outline" title="{% trans 'No action type details' %}">{% trans 'No action type details' %}</span>
|
||||
{% endfor %}
|
||||
@@ -63,7 +63,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'compensation:acc:action-edit' obj.id action.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit action' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{% fa5_icon 'file-alt' %}
|
||||
</button>
|
||||
</a>
|
||||
{% if has_access %}
|
||||
{% if is_entry_shared %}
|
||||
<button class="btn btn-default btn-modal mr-2" title="{% trans 'Resubmission' %}" data-form-url="{% url 'compensation:acc:resubmission-create' obj.id %}">
|
||||
{% fa5_icon 'bell' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'compensation:acc:new-deadline' obj.id %}" title="{% trans 'Add new deadline' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'calendar-check' %}
|
||||
@@ -58,7 +58,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'compensation:acc:deadline-edit' obj.id deadline.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit deadline' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<td class="align-middle">{{ deduction.surface|floatformat:2|intcomma }} m²</td>
|
||||
<td class="align-middle">{{ deduction.created.timestamp|default_if_none:""|naturalday}}</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access or is_default_member and user in deduction.intervention.shared_users %}
|
||||
{% if is_default_member and is_entry_shared or is_default_member and user in deduction.intervention.shared_users %}
|
||||
<button data-form-url="{% url 'compensation:acc:edit-deduction' deduction.account.id deduction.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit Deduction' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'compensation:acc:new-doc' obj.id %}" title="{% trans 'Add new document' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'file' %}
|
||||
@@ -57,7 +57,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'compensation:acc:edit-doc' obj.id doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit document' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'compensation:acc:new-state' obj.id %}" title="{% trans 'Add new state after' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'layer-group' %}
|
||||
@@ -35,7 +35,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Surface' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -51,14 +51,14 @@
|
||||
<span>{{ state.biotope_type.parent.long_name }} {% fa5_icon 'angle-right' %} {{ state.biotope_type.long_name }} ({{state.biotope_type.short_name}})</span>
|
||||
<br>
|
||||
{% for detail in state.biotope_type_details.all %}
|
||||
<span class="badge badge-pill rlp-r" title="{{detail}}">{{detail.long_name}}</span>
|
||||
<span class="badge badge-pill rlp-r" title="{{ detail.parent.short_name }} > {{detail}}">{{ detail.parent.short_name }} > {{ detail.long_name }}</span>
|
||||
{% empty %}
|
||||
<span class="badge badge-pill rlp-r-outline" title="{% trans 'No biotope type details' %}">{% trans 'No biotope type details' %}</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>{{ state.surface|floatformat:2 }} m²</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'compensation:acc:state-edit' obj.id state.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit state' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'compensation:acc:new-state' obj.id %}?before=true" title="{% trans 'Add new state before' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'layer-group' %}
|
||||
@@ -35,7 +35,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Surface' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -51,14 +51,14 @@
|
||||
<span>{{ state.biotope_type.parent.long_name }} {% fa5_icon 'angle-right' %} {{ state.biotope_type.long_name }} ({{state.biotope_type.short_name}})</span>
|
||||
<br>
|
||||
{% for detail in state.biotope_type_details.all %}
|
||||
<span class="badge badge-pill rlp-r" title="{{detail}}">{{detail.long_name}}</span>
|
||||
<span class="badge badge-pill rlp-r" title="{{ detail.parent.short_name }} > {{detail}}">{{ detail.parent.short_name }} > {{ detail.long_name }}</span>
|
||||
{% empty %}
|
||||
<span class="badge badge-pill rlp-r-outline" title="{% trans 'No biotope type details' %}">{% trans 'No biotope type details' %}</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>{{ state.surface|floatformat:2 }} m²</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'compensation:acc:state-edit' obj.id state.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit state' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
{% include 'user/includes/team_data_modal_button.html' %}
|
||||
{% endfor %}
|
||||
<hr>
|
||||
{% if has_access %}
|
||||
{% if is_entry_shared %}
|
||||
{% for user in obj.users.all %}
|
||||
{% include 'user/includes/contact_modal_button.html' %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -86,7 +86,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
|
||||
new_title = self.create_dummy_string()
|
||||
new_identifier = self.create_dummy_string()
|
||||
new_comment = self.create_dummy_string()
|
||||
new_geometry = MultiPolygon(srid=4326) # Create an empty geometry
|
||||
new_geometry = self.create_dummy_geometry()
|
||||
test_conservation_office = self.get_conservation_office_code()
|
||||
test_deductable_surface = self.eco_account.deductable_surface + 100
|
||||
|
||||
@@ -103,7 +103,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
|
||||
"identifier": new_identifier,
|
||||
"title": new_title,
|
||||
"comment": new_comment,
|
||||
"geom": new_geometry.geojson,
|
||||
"output": self.create_geojson(new_geometry),
|
||||
"surface": test_deductable_surface,
|
||||
"conservation_office": test_conservation_office.id
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ 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
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -103,11 +103,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",)
|
||||
@@ -179,11 +187,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",)
|
||||
@@ -259,7 +275,7 @@ def detail_view(request: HttpRequest, id: str):
|
||||
"last_checked_tooltip": last_checked_tooltip,
|
||||
"geom_form": geom_form,
|
||||
"parcels": parcels,
|
||||
"has_access": is_data_shared,
|
||||
"is_entry_shared": is_data_shared,
|
||||
"actions": actions,
|
||||
"before_states": before_states,
|
||||
"after_states": after_states,
|
||||
|
||||
@@ -12,11 +12,12 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from compensation.models import Compensation
|
||||
from konova.contexts import BaseContext
|
||||
from konova.decorators import uuid_required
|
||||
from konova.forms import SimpleGeomForm
|
||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
||||
from konova.utils.generators import generate_qr_code
|
||||
|
||||
|
||||
@uuid_required
|
||||
def report_view(request: HttpRequest, id: str):
|
||||
""" Renders the public report view
|
||||
|
||||
@@ -67,7 +68,7 @@ def report_view(request: HttpRequest, id: str):
|
||||
"img": qrcode_img_lanis,
|
||||
"url": qrcode_lanis_url,
|
||||
},
|
||||
"has_access": False, # disables action buttons during rendering
|
||||
"is_entry_shared": False, # disables action buttons during rendering
|
||||
"before_states": before_states,
|
||||
"after_states": after_states,
|
||||
"geom_form": geom_form,
|
||||
|
||||
@@ -23,7 +23,7 @@ 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
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -84,11 +84,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",)
|
||||
@@ -156,11 +164,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",)
|
||||
@@ -237,7 +253,7 @@ def detail_view(request: HttpRequest, id: str):
|
||||
"obj": acc,
|
||||
"geom_form": geom_form,
|
||||
"parcels": parcels,
|
||||
"has_access": is_data_shared,
|
||||
"is_entry_shared": is_data_shared,
|
||||
"before_states": before_states,
|
||||
"after_states": after_states,
|
||||
"sum_before_states": sum_before_states,
|
||||
|
||||
@@ -12,11 +12,13 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from compensation.models import EcoAccount
|
||||
from konova.contexts import BaseContext
|
||||
from konova.decorators import uuid_required
|
||||
from konova.forms import SimpleGeomForm
|
||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
||||
from konova.utils.generators import generate_qr_code
|
||||
|
||||
|
||||
@uuid_required
|
||||
def report_view(request: HttpRequest, id: str):
|
||||
""" Renders the public report view
|
||||
|
||||
@@ -73,7 +75,7 @@ def report_view(request: HttpRequest, id: str):
|
||||
"img": qrcode_img_lanis,
|
||||
"url": qrcode_lanis_url,
|
||||
},
|
||||
"has_access": False, # disables action buttons during rendering
|
||||
"is_entry_shared": False, # disables action buttons during rendering
|
||||
"before_states": before_states,
|
||||
"after_states": after_states,
|
||||
"geom_form": geom_form,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'ema:new-action' obj.id %}" title="{% trans 'Add new action' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'seedling' %}
|
||||
@@ -49,7 +49,7 @@
|
||||
<hr>
|
||||
{% endfor %}
|
||||
{% for detail in action.action_type_details.all %}
|
||||
<span class="badge badge-pill rlp-r" title="{{detail}}">{{detail.long_name}}</span>
|
||||
<span class="badge badge-pill rlp-r" title="{{ detail.parent.long_name }} > {{detail}}">{{ detail.parent.long_name }} > {{detail.long_name}}</span>
|
||||
{% empty %}
|
||||
<span class="badge badge-pill rlp-r-outline" title="{% trans 'No action type details' %}">{% trans 'No action type details' %}</span>
|
||||
{% endfor %}
|
||||
@@ -61,7 +61,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'ema:action-edit' obj.id action.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit action' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{% fa5_icon 'file-alt' %}
|
||||
</button>
|
||||
</a>
|
||||
{% if has_access %}
|
||||
{% if is_entry_shared %}
|
||||
<button class="btn btn-default btn-modal mr-2" title="{% trans 'Resubmission' %}" data-form-url="{% url 'ema:resubmission-create' obj.id %}">
|
||||
{% fa5_icon 'bell' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'ema:new-deadline' obj.id %}" title="{% trans 'Add new deadline' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'calendar-check' %}
|
||||
@@ -58,7 +58,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'ema:deadline-edit' obj.id deadline.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit deadline' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'ema:new-doc' obj.id %}" title="{% trans 'Add new document' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'file' %}
|
||||
@@ -57,7 +57,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'ema:edit-doc' obj.id doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit document' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'ema:new-state' obj.id %}" title="{% trans 'Add new state after' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'layer-group' %}
|
||||
@@ -49,14 +49,14 @@
|
||||
<span>{{ state.biotope_type.parent.long_name }} {% fa5_icon 'angle-right' %} {{ state.biotope_type.long_name }} ({{state.biotope_type.short_name}})</span>
|
||||
<br>
|
||||
{% for detail in state.biotope_type_details.all %}
|
||||
<span class="badge badge-pill rlp-r" title="{{detail}}">{{detail.long_name}}</span>
|
||||
<span class="badge badge-pill rlp-r" title="{{ detail.parent.short_name }} > {{detail}}">{{ detail.parent.short_name }} > {{ detail.long_name }}</span>
|
||||
{% empty %}
|
||||
<span class="badge badge-pill rlp-r-outline" title="{% trans 'No biotope type details' %}">{% trans 'No biotope type details' %}</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>{{ state.surface|floatformat:2 }} m²</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'ema:state-edit' obj.id state.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit state' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'ema:new-state' obj.id %}?before=true" title="{% trans 'Add new state before' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'layer-group' %}
|
||||
@@ -49,14 +49,14 @@
|
||||
<span>{{ state.biotope_type.parent.long_name }} {% fa5_icon 'angle-right' %} {{ state.biotope_type.long_name }} ({{state.biotope_type.short_name}})</span>
|
||||
<br>
|
||||
{% for detail in state.biotope_type_details.all %}
|
||||
<span class="badge badge-pill rlp-r" title="{{detail}}">{{detail.long_name}}</span>
|
||||
<span class="badge badge-pill rlp-r" title="{{ detail.parent.short_name }} > {{detail}}">{{ detail.parent.short_name }} > {{ detail.long_name }}</span>
|
||||
{% empty %}
|
||||
<span class="badge badge-pill rlp-r-outline" title="{% trans 'No biotope type details' %}">{% trans 'No biotope type details' %}</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>{{ state.surface|floatformat:2 }} m²</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'ema:state-edit' obj.id state.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit state' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
{% include 'user/includes/team_data_modal_button.html' %}
|
||||
{% endfor %}
|
||||
<hr>
|
||||
{% if has_access %}
|
||||
{% if is_entry_shared %}
|
||||
{% for user in obj.users.all %}
|
||||
{% include 'user/includes/contact_modal_button.html' %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -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)
|
||||
@@ -84,7 +84,7 @@ class EmaWorkflowTestCase(BaseWorkflowTestCase):
|
||||
new_title = self.create_dummy_string()
|
||||
new_identifier = self.create_dummy_string()
|
||||
new_comment = self.create_dummy_string()
|
||||
new_geometry = MultiPolygon(srid=4326) # Create an empty geometry
|
||||
new_geometry = self.create_dummy_geometry() # Create an empty geometry
|
||||
test_conservation_office = self.get_conservation_office_code()
|
||||
|
||||
check_on_elements = {
|
||||
@@ -99,7 +99,7 @@ class EmaWorkflowTestCase(BaseWorkflowTestCase):
|
||||
"identifier": new_identifier,
|
||||
"title": new_title,
|
||||
"comment": new_comment,
|
||||
"geom": new_geometry.geojson,
|
||||
"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)
|
||||
|
||||
@@ -24,7 +24,7 @@ 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
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -84,11 +84,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:
|
||||
@@ -142,7 +148,7 @@ def detail_view(request: HttpRequest, id: str):
|
||||
geom_form = SimpleGeomForm(instance=ema)
|
||||
parcels = ema.get_underlying_parcels()
|
||||
_user = request.user
|
||||
is_data_shared = ema.is_shared_with(_user)
|
||||
is_entry_shared = ema.is_shared_with(_user)
|
||||
|
||||
# Order states according to surface
|
||||
before_states = ema.before_states.all().order_by("-surface")
|
||||
@@ -167,7 +173,7 @@ def detail_view(request: HttpRequest, id: str):
|
||||
"obj": ema,
|
||||
"geom_form": geom_form,
|
||||
"parcels": parcels,
|
||||
"has_access": is_data_shared,
|
||||
"is_entry_shared": is_entry_shared,
|
||||
"before_states": before_states,
|
||||
"after_states": after_states,
|
||||
"sum_before_states": sum_before_states,
|
||||
@@ -215,11 +221,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",)
|
||||
|
||||
@@ -12,11 +12,12 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from ema.models import Ema
|
||||
from konova.contexts import BaseContext
|
||||
from konova.decorators import uuid_required
|
||||
from konova.forms import SimpleGeomForm
|
||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
||||
from konova.utils.generators import generate_qr_code
|
||||
|
||||
|
||||
@uuid_required
|
||||
def report_view(request:HttpRequest, id: str):
|
||||
""" Renders the public report view
|
||||
|
||||
@@ -67,7 +68,7 @@ def report_view(request:HttpRequest, id: str):
|
||||
"img": qrcode_img_lanis,
|
||||
"url": qrcode_lanis_url
|
||||
},
|
||||
"has_access": False, # disables action buttons during rendering
|
||||
"is_entry_shared": False, # disables action buttons during rendering
|
||||
"before_states": before_states,
|
||||
"after_states": after_states,
|
||||
"geom_form": geom_form,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<a href="{% url 'compensation:new' obj.id %}" title="{% trans 'Add new compensation' %}">
|
||||
<button class="btn btn-outline-default">
|
||||
{% fa5_icon 'plus' %}
|
||||
@@ -32,7 +32,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Title' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -51,7 +51,7 @@
|
||||
</td>
|
||||
<td class="align-middle">{{ comp.title }}</td>
|
||||
<td>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'intervention:remove-compensation' obj.id comp.id %}" class="btn btn-default btn-modal float-right" title="{% trans 'Remove compensation' %}">
|
||||
{% fa5_icon 'trash' %}
|
||||
</button>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{% fa5_icon 'file-alt' %}
|
||||
</button>
|
||||
</a>
|
||||
{% if has_access %}
|
||||
{% if is_entry_shared %}
|
||||
<button class="btn btn-default btn-modal mr-2" title="{% trans 'Resubmission' %}" data-form-url="{% url 'intervention:resubmission-create' obj.id %}">
|
||||
{% fa5_icon 'bell' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'intervention:new-deduction' obj.id %}" title="{% trans 'Add new deduction' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'tree' %}
|
||||
@@ -33,7 +33,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Created' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -56,7 +56,7 @@
|
||||
<td class="align-middle">{{ deduction.surface|floatformat:2|intcomma }} m²</td>
|
||||
<td class="align-middle">{{ deduction.created.timestamp|default_if_none:""|naturalday}}</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'intervention:edit-deduction' obj.id deduction.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit Deduction' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'intervention:new-doc' obj.id %}" title="{% trans 'Add new document' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'file' %}
|
||||
@@ -38,7 +38,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Comment' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -66,7 +66,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'intervention:edit-doc' obj.id doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit document' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'compensation:pay:new' obj.id %}" title="{% trans 'Add new payment' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'money-bill-wave' %}
|
||||
@@ -33,7 +33,7 @@
|
||||
<th class="w-50" scope="col">
|
||||
{% trans 'Comment' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -46,16 +46,24 @@
|
||||
{% for pay in obj.payments.all %}
|
||||
<tr>
|
||||
<td class="align-middle">
|
||||
{% if is_entry_shared %}
|
||||
{{ pay.amount|floatformat:2 }} €
|
||||
{% else %}
|
||||
***
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="align-middle">{{ pay.due_on|default_if_none:"---" }}</td>
|
||||
<td class="align-middle">
|
||||
<div class="scroll-150">
|
||||
{% if is_entry_shared %}
|
||||
{{ pay.comment }}
|
||||
{% else %}
|
||||
{% trans 'This data is not shared with you' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'compensation:pay:edit' obj.id pay.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit payment' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
{% comment %}
|
||||
Only show add-button if no revocation exists, yet.
|
||||
{% endcomment %}
|
||||
{% if is_default_member and has_access and not obj.legal.revocation %}
|
||||
{% if is_default_member and is_entry_shared and not obj.legal.revocation %}
|
||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'intervention:new-revocation' obj.id %}" title="{% trans 'Add revocation' %}">
|
||||
{% fa5_icon 'plus' %}
|
||||
{% fa5_icon 'ban' %}
|
||||
@@ -36,7 +36,7 @@
|
||||
<th scope="col">
|
||||
{% trans 'Comment' %}
|
||||
</th>
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<th class="w-10" scope="col">
|
||||
<span class="float-right">
|
||||
{% trans 'Action' %}
|
||||
@@ -64,7 +64,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
{% if is_default_member and is_entry_shared %}
|
||||
<button data-form-url="{% url 'intervention:edit-revocation' obj.id rev.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit revocation' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
{% include 'user/includes/team_data_modal_button.html' %}
|
||||
{% endfor %}
|
||||
<hr>
|
||||
{% if has_access %}
|
||||
{% if is_entry_shared %}
|
||||
{% for user in obj.users.all %}
|
||||
{% include 'user/includes/contact_modal_button.html' %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -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)
|
||||
@@ -124,7 +124,7 @@ class EditInterventionFormTestCase(NewInterventionFormTestCase):
|
||||
self.assertIsNotNone(obj.responsible.handler)
|
||||
self.assertEqual(obj.title, data["title"])
|
||||
self.assertEqual(obj.comment, data["comment"])
|
||||
self.assertTrue(test_geom.equals_exact(obj.geometry.geom, 0.000001))
|
||||
self.assert_equal_geometries(test_geom, obj.geometry.geom)
|
||||
|
||||
self.assertEqual(obj.legal.binding_date, today)
|
||||
self.assertEqual(obj.legal.registration_date, today)
|
||||
|
||||
@@ -23,7 +23,8 @@ 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
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -88,11 +89,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",)
|
||||
@@ -185,7 +194,7 @@ def detail_view(request: HttpRequest, id: str):
|
||||
"last_checked": last_checked,
|
||||
"last_checked_tooltip": last_checked_tooltip,
|
||||
"compensations": compensations,
|
||||
"has_access": is_data_shared,
|
||||
"is_entry_shared": is_data_shared,
|
||||
"geom_form": geom_form,
|
||||
"is_default_member": _user.in_group(DEFAULT_GROUP),
|
||||
"is_zb_member": _user.in_group(ZB_GROUP),
|
||||
@@ -236,11 +245,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",)
|
||||
|
||||
@@ -11,7 +11,7 @@ from uuid import UUID
|
||||
|
||||
from bootstrap_modal_forms.mixins import is_ajax
|
||||
from django.contrib import messages
|
||||
from django.http import Http404
|
||||
from django.core.exceptions import BadRequest
|
||||
from django.shortcuts import redirect, get_object_or_404, render
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@@ -185,7 +185,7 @@ def uuid_required(function):
|
||||
try:
|
||||
uuid = UUID(uuid)
|
||||
except ValueError:
|
||||
raise Http404(
|
||||
raise BadRequest(
|
||||
"Invalid UUID"
|
||||
)
|
||||
return function(request, *args, **kwargs)
|
||||
|
||||
55
konova/filters/mixins/user_log.py
Normal file
55
konova/filters/mixins/user_log.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Author: Michel Peltriaux
|
||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
||||
Contact: ksp-servicestelle@sgdnord.rlp.de
|
||||
Created on: 19.08.24
|
||||
|
||||
"""
|
||||
import django_filters
|
||||
from django import forms
|
||||
from django.db.models import QuerySet, Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class UserLoggedTableFilterMixin(django_filters.FilterSet):
|
||||
ul = django_filters.CharFilter(
|
||||
method="filter_user_log",
|
||||
label=_(""),
|
||||
label_suffix=_(""),
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"placeholder": _("Logged user"),
|
||||
"title": _("Search for entries where this person has been participated according to log history"),
|
||||
"class": "form-control",
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def filter_user_log(self, queryset, name, value) -> QuerySet:
|
||||
""" Filters queryset depending on value of input
|
||||
|
||||
Args:
|
||||
queryset (QuerySet): Incoming (prefiltered) queryset
|
||||
name (str): Name of input field
|
||||
value (str): Value of input field
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
value = value.replace(",", " ")
|
||||
value = value.strip()
|
||||
values = value.split(" ")
|
||||
|
||||
q = Q()
|
||||
for val in values:
|
||||
q &= (
|
||||
Q(log__user__username__icontains=val) |
|
||||
Q(log__user__first_name__icontains=val) |
|
||||
Q(log__user__last_name__icontains=val)
|
||||
)
|
||||
|
||||
queryset = queryset.filter(q)
|
||||
return queryset
|
||||
@@ -14,6 +14,7 @@ from konova.filters.mixins.office import ConservationOfficeTableFilterMixin, Reg
|
||||
from konova.filters.mixins.record import RecordableTableFilterMixin
|
||||
from konova.filters.mixins.self_created import SelfCreatedTableFilterMixin
|
||||
from konova.filters.mixins.share import ShareableTableFilterMixin
|
||||
from konova.filters.mixins.user_log import UserLoggedTableFilterMixin
|
||||
|
||||
|
||||
class AbstractTableFilter(django_filters.FilterSet):
|
||||
@@ -40,7 +41,8 @@ class SelectionTableFilter(RegistrationOfficeTableFilterMixin,
|
||||
|
||||
class QueryTableFilter(KeywordTableFilterMixin,
|
||||
FileNumberTableFilterMixin,
|
||||
GeoReferencedTableFilterMixin):
|
||||
GeoReferencedTableFilterMixin,
|
||||
UserLoggedTableFilterMixin):
|
||||
""" TableFilter holding different filter options for query related filtering
|
||||
|
||||
"""
|
||||
|
||||
@@ -25,15 +25,16 @@ class SimpleGeomForm(BaseForm):
|
||||
""" A geometry form for rendering geometry read-only using a widget
|
||||
|
||||
"""
|
||||
read_only = True
|
||||
geometry_simplified = False
|
||||
geom = JSONField(
|
||||
read_only: bool = True
|
||||
_geometry_simplified: bool = False
|
||||
output = JSONField(
|
||||
label=_("Geometry"),
|
||||
help_text=_(""),
|
||||
label_suffix="",
|
||||
required=False,
|
||||
disabled=False,
|
||||
)
|
||||
_num_geometries_ignored: int = 0
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.read_only = kwargs.pop("read_only", True)
|
||||
@@ -48,33 +49,33 @@ 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
|
||||
geom = ""
|
||||
self.empty = True
|
||||
|
||||
self.initialize_form_field("geom", geom)
|
||||
self.initialize_form_field("output", geom)
|
||||
|
||||
def is_valid(self):
|
||||
super().is_valid()
|
||||
is_valid = True
|
||||
|
||||
# Get geojson from form
|
||||
geom = self.data["geom"]
|
||||
geom = self.data.get("output", None)
|
||||
if geom is None or len(geom) == 0:
|
||||
# empty geometry is a valid geometry
|
||||
self.cleaned_data["geom"] = MultiPolygon(srid=DEFAULT_SRID_RLP).ewkt
|
||||
self.cleaned_data["output"] = MultiPolygon(srid=DEFAULT_SRID_RLP).ewkt
|
||||
return is_valid
|
||||
geom = json.loads(geom)
|
||||
|
||||
# Write submitted data back into form field to make sure invalid geometry
|
||||
# will be rendered again on failed submit
|
||||
self.initialize_form_field("geom", self.data["geom"])
|
||||
self.initialize_form_field("output", self.data["output"])
|
||||
|
||||
# Read geojson into gdal geometry
|
||||
# HINT: This can be simplified if the geojson format holds data in epsg:4326 (GDAL provides direct creation for
|
||||
# this case)
|
||||
# Initialize features list with empty MultiPolygon, so that an empty input will result in a
|
||||
# proper empty MultiPolygon object
|
||||
features = []
|
||||
features_json = geom.get("features", [])
|
||||
accepted_ogr_types = [
|
||||
@@ -97,33 +98,41 @@ class SimpleGeomForm(BaseForm):
|
||||
g = self.__flatten_geom_to_2D(g)
|
||||
|
||||
if g.geom_type not in accepted_ogr_types:
|
||||
self.add_error("geom", _("Only surfaces allowed. Points or lines must be buffered."))
|
||||
self.add_error("output", _("Only surfaces allowed. Points or lines must be buffered."))
|
||||
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
|
||||
|
||||
polygon = Polygon.from_ewkt(g.ewkt)
|
||||
is_valid &= polygon.valid
|
||||
if not polygon.valid:
|
||||
self.add_error("geom", polygon.valid_reason)
|
||||
g = Polygon.from_ewkt(g.ewkt)
|
||||
is_valid &= g.valid
|
||||
if not g.valid:
|
||||
self.add_error("output", g.valid_reason)
|
||||
return is_valid
|
||||
|
||||
features.append(polygon)
|
||||
if isinstance(g, Polygon):
|
||||
features.append(g)
|
||||
elif isinstance(g, MultiPolygon):
|
||||
features.extend(list(g))
|
||||
|
||||
# Unionize all geometry features into one new MultiPolygon
|
||||
if features:
|
||||
form_geom = MultiPolygon(*features, srid=DEFAULT_SRID_RLP).unary_union
|
||||
else:
|
||||
form_geom = MultiPolygon(srid=DEFAULT_SRID_RLP)
|
||||
for feature in features:
|
||||
form_geom = form_geom.union(feature)
|
||||
|
||||
# Make sure to convert into a MultiPolygon. Relevant if a single Polygon is provided.
|
||||
if form_geom.geom_type != "MultiPolygon":
|
||||
form_geom = MultiPolygon(form_geom, srid=DEFAULT_SRID_RLP)
|
||||
form_geom = Geometry.cast_to_multipolygon(form_geom)
|
||||
|
||||
# Write unioned Multipolygon into cleaned data
|
||||
if self.cleaned_data is None:
|
||||
self.cleaned_data = {}
|
||||
self.cleaned_data["geom"] = form_geom.ewkt
|
||||
self.cleaned_data["output"] = form_geom.ewkt
|
||||
|
||||
return is_valid
|
||||
|
||||
@@ -133,7 +142,7 @@ class SimpleGeomForm(BaseForm):
|
||||
Returns:
|
||||
|
||||
"""
|
||||
geom = self.cleaned_data.get("geom")
|
||||
geom = self.cleaned_data.get("output")
|
||||
g = gdal.OGRGeometry(geom, srs=DEFAULT_SRID_RLP)
|
||||
num_vertices = g.num_coords
|
||||
|
||||
@@ -146,15 +155,6 @@ class SimpleGeomForm(BaseForm):
|
||||
|
||||
"""
|
||||
is_area_valid = geom.area > 1 # > 1m² (SRID:25832)
|
||||
|
||||
if not is_area_valid:
|
||||
self.add_error(
|
||||
"geom",
|
||||
_("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):
|
||||
@@ -192,14 +192,14 @@ class SimpleGeomForm(BaseForm):
|
||||
if self.instance is None or self.instance.geometry is None:
|
||||
raise LookupError
|
||||
geometry = self.instance.geometry
|
||||
geometry.geom = self.cleaned_data.get("geom", MultiPolygon(srid=DEFAULT_SRID_RLP))
|
||||
geometry.geom = self.cleaned_data.get("output", MultiPolygon(srid=DEFAULT_SRID_RLP))
|
||||
geometry.modified = action
|
||||
|
||||
geometry.save()
|
||||
except LookupError:
|
||||
# No geometry or linked instance holding a geometry exist --> create a new one!
|
||||
geometry = Geometry.objects.create(
|
||||
geom=self.cleaned_data.get("geom", MultiPolygon(srid=DEFAULT_SRID_RLP)),
|
||||
geom=self.cleaned_data.get("output", MultiPolygon(srid=DEFAULT_SRID_RLP)),
|
||||
created=action,
|
||||
)
|
||||
|
||||
@@ -207,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
|
||||
@@ -223,3 +239,20 @@ class SimpleGeomForm(BaseForm):
|
||||
g_wkt = wkt_w.write(geom.geos).decode("utf-8")
|
||||
geom = gdal.OGRGeometry(g_wkt)
|
||||
return geom
|
||||
|
||||
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
|
||||
"""
|
||||
features = geojson.get("features", [])
|
||||
for feature in features:
|
||||
feature["properties"]["editable"] = not self.read_only
|
||||
if title:
|
||||
feature["properties"]["title"] = title
|
||||
return geojson
|
||||
|
||||
@@ -6,11 +6,11 @@ Created on: 26.10.22
|
||||
|
||||
"""
|
||||
import zipfile
|
||||
from datetime import datetime
|
||||
from io import BytesIO
|
||||
|
||||
from django.core.mail import EmailMessage
|
||||
from django.utils import timezone
|
||||
from django.utils.datetime_safe import datetime
|
||||
|
||||
from analysis.utils.excel.excel import TempExcelFile
|
||||
from analysis.utils.report import TimespanReport
|
||||
|
||||
88
konova/management/commands/recalculate_parcels.py
Normal file
88
konova/management/commands/recalculate_parcels.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""
|
||||
Author: Michel Peltriaux
|
||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
||||
Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 04.01.22
|
||||
|
||||
"""
|
||||
import datetime
|
||||
|
||||
from django.contrib.gis.db.models.functions import Area
|
||||
|
||||
from konova.management.commands.setup import BaseKonovaCommand
|
||||
from konova.models import Geometry, ParcelIntersection
|
||||
|
||||
|
||||
class Command(BaseKonovaCommand):
|
||||
help = "Recalculates parcels for entries with geometry but missing parcel information"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
"--force-all",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="If Attribute set, all entries parcels will be recalculated"
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
try:
|
||||
self.recalculate_parcels(options)
|
||||
except KeyboardInterrupt:
|
||||
self._break_line()
|
||||
exit(-1)
|
||||
|
||||
def recalculate_parcels(self, options: dict):
|
||||
force_all = options.get("force_all", False)
|
||||
|
||||
geometry_objects = Geometry.objects.filter(
|
||||
geom__isempty=False,
|
||||
).exclude(
|
||||
geom=None
|
||||
)
|
||||
|
||||
if not force_all:
|
||||
# Fetch all intersections
|
||||
intersection_objs = ParcelIntersection.objects.filter(
|
||||
geometry__in=geometry_objects
|
||||
)
|
||||
# Just take the geometry ids, which seem to have intersections
|
||||
geom_with_intersection_ids = intersection_objs.values_list(
|
||||
"geometry__id",
|
||||
flat=True
|
||||
)
|
||||
# ... and resolve into Geometry objects again ...
|
||||
intersected_geom_objs = Geometry.objects.filter(
|
||||
id__in=geom_with_intersection_ids
|
||||
)
|
||||
# ... to be able to use the way more efficient difference() function ...
|
||||
geometry_objects_ids = geometry_objects.difference(intersected_geom_objs).values_list("id", flat=True)
|
||||
# ... so we can resolve these into proper Geometry objects again for further annotation usage
|
||||
geometry_objects = Geometry.objects.filter(id__in=geometry_objects_ids)
|
||||
|
||||
self._write_warning("=== Update parcels and districts ===")
|
||||
# Order geometries by size to process smaller once at first
|
||||
geometries = geometry_objects.annotate(
|
||||
area=Area("geom")
|
||||
).order_by(
|
||||
'area'
|
||||
)
|
||||
self._write_warning(f"Process parcels for {geometries.count()} geometry entries now ...")
|
||||
i = 0
|
||||
num_geoms = geometries.count()
|
||||
geoms_with_errors = {}
|
||||
for geometry in geometries:
|
||||
self._write_warning(f"--- {datetime.datetime.now()} Process {geometry.id} now ...")
|
||||
try:
|
||||
geometry.update_parcels()
|
||||
self._write_warning(f"--- Processed {geometry.get_underlying_parcels().count()} underlying parcels")
|
||||
except Exception as e:
|
||||
geoms_with_errors[geometry.id] = str(e)
|
||||
i += 1
|
||||
self._write_warning(f"--- {i}/{num_geoms} processed")
|
||||
|
||||
self._write_success("Updating parcels done!")
|
||||
|
||||
for key, val in geoms_with_errors.items():
|
||||
self._write_error(f" Error on {key}: {val}")
|
||||
self._write_success(f"{num_geoms - len(geoms_with_errors)} geometries successfuly recalculated!")
|
||||
self._break_line()
|
||||
@@ -1,51 +0,0 @@
|
||||
"""
|
||||
Author: Michel Peltriaux
|
||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
||||
Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 19.08.21
|
||||
|
||||
"""
|
||||
from django.core.management import BaseCommand
|
||||
|
||||
from intervention.models import Intervention
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Performs test on collisions using the identifier generation"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
identifiers = {}
|
||||
max_iterations = 100000
|
||||
try:
|
||||
collisions = 0
|
||||
len_ids = len(identifiers)
|
||||
while len_ids < max_iterations:
|
||||
tmp_intervention = Intervention()
|
||||
_id = tmp_intervention.generate_new_identifier()
|
||||
len_ids = len(identifiers)
|
||||
if _id not in identifiers:
|
||||
if len_ids % (max_iterations/5) == 0:
|
||||
print(len_ids)
|
||||
identifiers[_id] = None
|
||||
else:
|
||||
collisions += 1
|
||||
print("+++ Collision after {} identifiers +++".format(len_ids))
|
||||
|
||||
except KeyboardInterrupt:
|
||||
self._break_line()
|
||||
exit(-1)
|
||||
print(
|
||||
"\n{} collisions in {} identifiers; Collision rate {}%".format(
|
||||
collisions,
|
||||
len_ids,
|
||||
(collisions / len_ids)*100,
|
||||
)
|
||||
)
|
||||
|
||||
def _break_line(self):
|
||||
""" Simply prints a line break
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
self.stdout.write("\n")
|
||||
@@ -1,54 +0,0 @@
|
||||
"""
|
||||
Author: Michel Peltriaux
|
||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
||||
Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 04.01.22
|
||||
|
||||
"""
|
||||
import datetime
|
||||
|
||||
from django.contrib.gis.db.models.functions import Area
|
||||
|
||||
from konova.management.commands.setup import BaseKonovaCommand
|
||||
from konova.models import Geometry, Parcel, District
|
||||
|
||||
|
||||
class Command(BaseKonovaCommand):
|
||||
help = "Checks the database' sanity and removes unused entries"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
try:
|
||||
self.update_all_parcels()
|
||||
except KeyboardInterrupt:
|
||||
self._break_line()
|
||||
exit(-1)
|
||||
|
||||
def update_all_parcels(self):
|
||||
num_parcels_before = Parcel.objects.count()
|
||||
num_districts_before = District.objects.count()
|
||||
self._write_warning("=== Update parcels and districts ===")
|
||||
# Order geometries by size to process smaller once at first
|
||||
geometries = Geometry.objects.all().exclude(
|
||||
geom=None
|
||||
).annotate(area=Area("geom")).order_by(
|
||||
'area'
|
||||
)
|
||||
self._write_warning(f"Process parcels for {geometries.count()} geometry entries now ...")
|
||||
i = 0
|
||||
num_geoms = geometries.count()
|
||||
for geometry in geometries:
|
||||
self._write_warning(f"--- {datetime.datetime.now()} Process {geometry.id} now ...")
|
||||
geometry.update_parcels()
|
||||
self._write_warning(f"--- Processed {geometry.get_underlying_parcels().count()} underlying parcels")
|
||||
i += 1
|
||||
self._write_warning(f"--- {i}/{num_geoms} processed")
|
||||
|
||||
num_parcels_after = Parcel.objects.count()
|
||||
num_districts_after = District.objects.count()
|
||||
if num_parcels_after != num_parcels_before:
|
||||
self._write_error(f"Parcels have changed: {num_parcels_before} to {num_parcels_after} entries. You should run the sanitize command.")
|
||||
if num_districts_after != num_districts_before:
|
||||
self._write_error(f"Districts have changed: {num_districts_before} to {num_districts_after} entries. You should run the sanitize command.")
|
||||
|
||||
self._write_success("Updating parcels done!")
|
||||
self._break_line()
|
||||
@@ -8,9 +8,10 @@ Created on: 15.11.21
|
||||
import json
|
||||
|
||||
from django.contrib.gis.db.models import MultiPolygonField
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
|
||||
from django.db import models, transaction
|
||||
from django.utils import timezone
|
||||
from django.contrib.gis.geos import MultiPolygon
|
||||
|
||||
from konova.models import BaseResource, UuidModel
|
||||
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
|
||||
@@ -223,6 +224,17 @@ class Geometry(BaseResource):
|
||||
)
|
||||
parcel_obj.updated_on = _now
|
||||
parcels_to_update.append(parcel_obj)
|
||||
except MultipleObjectsReturned:
|
||||
parcel_obj = Parcel.make_unique(
|
||||
district=district,
|
||||
municipal=municipal,
|
||||
parcel_group=parcel_group,
|
||||
flr=flr_val,
|
||||
flrstck_nnr=flrstck_nnr,
|
||||
flrstck_zhlr=flrstck_zhlr,
|
||||
)
|
||||
parcel_obj.updated_on = _now
|
||||
parcels_to_update.append(parcel_obj)
|
||||
except ObjectDoesNotExist:
|
||||
# If not existing, create object but do not commit, yet
|
||||
parcel_obj = Parcel(
|
||||
@@ -331,6 +343,7 @@ class Geometry(BaseResource):
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": json.loads(p.json),
|
||||
"properties": {},
|
||||
}
|
||||
for p in polygons
|
||||
]
|
||||
@@ -366,13 +379,42 @@ class Geometry(BaseResource):
|
||||
diff = geom_envelope - self.geom
|
||||
|
||||
if diff.area == 0:
|
||||
ratio = 1
|
||||
complexity_factor = 1
|
||||
else:
|
||||
ratio = self.geom.area / diff.area
|
||||
complexity_factor = self.geom.area / diff.area
|
||||
|
||||
complexity_factor = 1 - ratio
|
||||
return complexity_factor
|
||||
|
||||
@staticmethod
|
||||
def cast_to_multipolygon(input_geom):
|
||||
""" If input_geom is not a MultiPolygon, cast to MultiPolygon
|
||||
|
||||
Args:
|
||||
input_geom ():
|
||||
|
||||
Returns:
|
||||
output_geom
|
||||
"""
|
||||
output_geom = input_geom
|
||||
if not isinstance(input_geom, MultiPolygon):
|
||||
output_geom = MultiPolygon(input_geom, srid=DEFAULT_SRID_RLP)
|
||||
return output_geom
|
||||
|
||||
@staticmethod
|
||||
def cast_to_rlp_srid(input_geom):
|
||||
""" If input_geom is not of RLP SRID (25832), cast to RLP SRID
|
||||
|
||||
Args:
|
||||
input_geom ():
|
||||
|
||||
Returns:
|
||||
output_geom
|
||||
"""
|
||||
output_geom = input_geom
|
||||
if output_geom.srid != DEFAULT_SRID_RLP:
|
||||
output_geom.transform(DEFAULT_SRID_RLP)
|
||||
return output_geom
|
||||
|
||||
|
||||
class GeometryConflict(UuidModel):
|
||||
"""
|
||||
|
||||
@@ -5,7 +5,7 @@ Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 16.12.21
|
||||
|
||||
"""
|
||||
from django.db import models
|
||||
from django.db import models, transaction
|
||||
|
||||
from konova.models import UuidModel
|
||||
|
||||
@@ -158,6 +158,46 @@ class Parcel(UuidModel):
|
||||
def __str__(self):
|
||||
return f"{self.parcel_group} | {self.flr} | {self.flrstck_zhlr} | {self.flrstck_nnr}"
|
||||
|
||||
@classmethod
|
||||
def make_unique(cls, **kwargs):
|
||||
""" Checks for duplicates of a Parcel, choose a (now) unique one,
|
||||
repairs relations for ParcelIntersection and removes duplicates.
|
||||
|
||||
Args:
|
||||
**kwargs ():
|
||||
|
||||
Returns:
|
||||
unique_true (Parcel): The new unique 'true one'
|
||||
"""
|
||||
parcel_objs = Parcel.objects.filter(**kwargs)
|
||||
|
||||
if not parcel_objs.exists():
|
||||
return None
|
||||
|
||||
# Get one of the found parcels and use it as new 'true one'
|
||||
unique_parcel = parcel_objs.first()
|
||||
# separate it from the rest
|
||||
parcel_objs = parcel_objs.exclude(id=unique_parcel.id)
|
||||
|
||||
if not parcel_objs.exists():
|
||||
# There are no duplicates - all good, just return
|
||||
return unique_parcel
|
||||
|
||||
# Fetch existing intersections, which still point on the duplicated parcels
|
||||
intersection_objs = ParcelIntersection.objects.filter(
|
||||
parcel__in=parcel_objs
|
||||
)
|
||||
|
||||
# Change each intersection, so they point on the 'true one' parcel from now on
|
||||
for intersection in intersection_objs:
|
||||
intersection.parcel = unique_parcel
|
||||
intersection.save()
|
||||
|
||||
# Remove the duplicated parcels
|
||||
parcel_objs.delete()
|
||||
|
||||
return unique_parcel
|
||||
|
||||
|
||||
class ParcelIntersection(UuidModel):
|
||||
"""
|
||||
|
||||
@@ -279,3 +279,17 @@ Similar to bootstraps 'shadow-lg'
|
||||
.alert{
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/*
|
||||
Overwrites netgis.css attributes
|
||||
*/
|
||||
.netgis-gradient-a{
|
||||
/*
|
||||
Overwrites gradient used on default css of netgis map client
|
||||
*/
|
||||
background: var(--rlp-red) !important;
|
||||
}
|
||||
|
||||
.netgis-menu{
|
||||
z-index: 1 !important;
|
||||
}
|
||||
BIN
konova/static/images/error_imgs/croc_technician_400.png
Normal file
BIN
konova/static/images/error_imgs/croc_technician_400.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
BIN
konova/static/images/error_imgs/croc_technician_500.png
Normal file
BIN
konova/static/images/error_imgs/croc_technician_500.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
@@ -66,7 +66,6 @@ INSTALLED_APPS = [
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.gis',
|
||||
'django.contrib.humanize',
|
||||
'simple_sso.sso_server',
|
||||
'django_tables2',
|
||||
'bootstrap_modal_forms',
|
||||
'fontawesome_5',
|
||||
@@ -189,7 +188,6 @@ STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
||||
STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, 'konova/static'),
|
||||
os.path.join(BASE_DIR, 'templates/map/client'), # NETGIS map client files
|
||||
os.path.join(BASE_DIR, 'templates/map/client/libs'), # NETGIS map client files
|
||||
]
|
||||
|
||||
# EMAIL (see https://docs.djangoproject.com/en/dev/topics/email/)
|
||||
|
||||
@@ -5,6 +5,7 @@ Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 31.01.22
|
||||
|
||||
"""
|
||||
from konova.sub_settings.django_settings import env
|
||||
|
||||
# MAPS
|
||||
DEFAULT_LAT = 50.00
|
||||
@@ -28,3 +29,6 @@ LANIS_ZOOM_LUT = {
|
||||
1000: 30,
|
||||
500: 31,
|
||||
}
|
||||
|
||||
MAP_PROXY_HOST_WHITELIST = env.list("MAP_PROXY_HOST_WHITELIST")
|
||||
i = 0
|
||||
@@ -16,3 +16,5 @@ OAUTH_CODE_VERIFIER = env("OAUTH_CODE_VERIFIER")
|
||||
|
||||
OAUTH_CLIENT_ID = env("OAUTH_CLIENT_ID")
|
||||
OAUTH_CLIENT_SECRET = env("OAUTH_CLIENT_SECRET")
|
||||
|
||||
PROPAGATION_SECRET = env("PROPAGATION_SECRET")
|
||||
|
||||
@@ -124,6 +124,7 @@ class GeometryTestCase(BaseTestCase):
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": json.loads(p.json),
|
||||
"properties": {}
|
||||
}
|
||||
for p in polygons
|
||||
]
|
||||
|
||||
@@ -469,7 +469,7 @@ class BaseTestCase(TestCase):
|
||||
eco_account.save()
|
||||
return eco_account
|
||||
|
||||
def assert_equal_geometries(self, geom1: MultiPolygon, geom2: MultiPolygon, tolerance = 0.001):
|
||||
def assert_equal_geometries(self, geom1: MultiPolygon, geom2: MultiPolygon, tolerance=0.001):
|
||||
""" Assert for geometries to be equal
|
||||
|
||||
Transforms the geometries to matching srids before checking
|
||||
@@ -491,7 +491,10 @@ class BaseTestCase(TestCase):
|
||||
# transformation from one coordinate system into the other, which is valid
|
||||
geom1.transform(geom2.srid)
|
||||
geom2.transform(geom1.srid)
|
||||
self.assertTrue(geom1.equals_exact(geom2, tolerance) or geom2.equals_exact(geom1, tolerance))
|
||||
self.assertTrue(
|
||||
geom1.equals_exact(geom2, tolerance=tolerance),
|
||||
msg=f"Difference is {abs(geom1.area - geom2.area)} with {geom1.area} and {geom2.area} in a tolerance of {tolerance}"
|
||||
)
|
||||
|
||||
|
||||
class BaseViewTestCase(BaseTestCase):
|
||||
|
||||
@@ -42,5 +42,6 @@ urlpatterns = [
|
||||
path('client/proxy/wfs', ClientProxyParcelWFS.as_view(), name="client-proxy-wfs"),
|
||||
]
|
||||
|
||||
handler400 = "konova.views.error.get_400_view"
|
||||
handler404 = "konova.views.error.get_404_view"
|
||||
handler500 = "konova.views.error.get_500_view"
|
||||
|
||||
@@ -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")
|
||||
@@ -91,3 +92,6 @@ INTERVENTION_HAS_REVOCATIONS_TEMPLATE = _("This intervention has {} revocations"
|
||||
DATA_CHECKED_ON_TEMPLATE = _("Checked on {} by {}")
|
||||
DATA_CHECKED_PREVIOUSLY_TEMPLATE = _("Data has changed since last check on {} by {}")
|
||||
DATA_IS_UNCHECKED = _("Current data not checked yet")
|
||||
|
||||
# API TOKEN SETTINGS
|
||||
NEW_API_TOKEN_GENERATED = _("New token generated. Administrators need to validate.")
|
||||
@@ -1,78 +0,0 @@
|
||||
"""
|
||||
Author: Michel Peltriaux
|
||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
||||
Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 17.08.21
|
||||
|
||||
"""
|
||||
from collections import Iterable
|
||||
|
||||
import requests
|
||||
from user.models import User
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from konova.settings import SSO_SERVER_BASE, SSO_PUBLIC_KEY, PROXIES
|
||||
from konova.sub_settings.context_settings import BASE_TITLE_SHORT
|
||||
|
||||
|
||||
class Messenger:
|
||||
""" Used to send messages to the SSO server.
|
||||
|
||||
Messages can be seen by the user the next time they login on their SSO dashboard.
|
||||
Documentation for SSO Server-Client communication can be found here:
|
||||
https://git.naturschutz.rlp.de/SGD-Nord/arnova/wiki/Messages
|
||||
|
||||
"""
|
||||
server_url = "{}communication/message/".format(SSO_SERVER_BASE)
|
||||
|
||||
def __init__(self, users: Iterable, subject: str = None, body: str = None, type: str = None):
|
||||
self.users = users
|
||||
self.msg_subject = subject
|
||||
self.msg_body = body
|
||||
self.msg_type = type
|
||||
|
||||
def send(self):
|
||||
""" Sends a message
|
||||
|
||||
"""
|
||||
if self.msg_body is None or len(self.msg_body) == 0:
|
||||
raise AttributeError("No message body set")
|
||||
|
||||
headers = {
|
||||
"x-services-public-key": SSO_PUBLIC_KEY
|
||||
}
|
||||
for user in self.users:
|
||||
data = {
|
||||
"type": self.msg_type,
|
||||
"sender": BASE_TITLE_SHORT,
|
||||
"receiver": user.username,
|
||||
"subject": self.msg_subject,
|
||||
"body": self.msg_body,
|
||||
}
|
||||
requests.post(
|
||||
self.server_url,
|
||||
data=data,
|
||||
headers=headers,
|
||||
proxies=PROXIES
|
||||
)
|
||||
|
||||
def send_object_checked(self, obj_identifier: str, performing_user: User, detail_view_url: str = ""):
|
||||
""" Wraps sending of a message related to the checking of an object, like an intervention
|
||||
|
||||
Args:
|
||||
obj_identifier (str): The object's identifier (e.g. 'EIV-123'
|
||||
performing_user (User): The user who performed the checking
|
||||
detail_view_url (str): If a direct link to the object shall be added to the message, it can be provided here
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
self.msg_subject = _("{} checked").format(obj_identifier)
|
||||
if len(detail_view_url) > 0:
|
||||
detail_view_url = _('<a href="{}">Check it out</a>').format(detail_view_url)
|
||||
self.msg_body = _("{} has been checked successfully by user {}! {}").format(
|
||||
obj_identifier,
|
||||
performing_user.username,
|
||||
detail_view_url
|
||||
)
|
||||
self.send()
|
||||
@@ -11,6 +11,7 @@ from json import JSONDecodeError
|
||||
import requests
|
||||
|
||||
from konova.sub_settings import schneider_settings
|
||||
from konova.sub_settings.lanis_settings import DEFAULT_SRID
|
||||
from konova.sub_settings.proxy_settings import PROXIES
|
||||
|
||||
|
||||
@@ -34,6 +35,7 @@ class ParcelFetcher:
|
||||
if geom.area < buffer_threshold:
|
||||
# Fallback for malicious geometries which are way too small and would disappear on negative buffering
|
||||
geom = geometry.geom
|
||||
geom.transform(DEFAULT_SRID)
|
||||
self.geojson = geom.ewkt
|
||||
self.results = []
|
||||
|
||||
@@ -55,11 +57,11 @@ class ParcelFetcher:
|
||||
content = json.loads(response.content.decode("utf-8"))
|
||||
except JSONDecodeError:
|
||||
content = {}
|
||||
next = content.get("next", None)
|
||||
_next = content.get("next", None)
|
||||
fetched_parcels = content.get("results", [])
|
||||
self.results += fetched_parcels
|
||||
|
||||
if next:
|
||||
self.get_parcels(next)
|
||||
if _next:
|
||||
self.get_parcels(_next)
|
||||
|
||||
return self.results
|
||||
@@ -216,11 +216,11 @@ class TableRenderMixin:
|
||||
|
||||
"""
|
||||
html = ""
|
||||
has_access = record.is_shared_with(self.user)
|
||||
is_entry_shared = record.is_shared_with(self.user)
|
||||
|
||||
html += self.render_icn(
|
||||
tooltip=_("Full access granted") if has_access else _("Access not granted"),
|
||||
icn_class="fas fa-edit rlp-r-inv" if has_access else "far fa-edit",
|
||||
tooltip=_("Full access granted") if is_entry_shared else _("Access not granted"),
|
||||
icn_class="fas fa-edit rlp-r-inv" if is_entry_shared else "far fa-edit",
|
||||
)
|
||||
return format_html(html)
|
||||
|
||||
|
||||
@@ -25,6 +25,20 @@ def get_404_view(request: HttpRequest, exception=None):
|
||||
return render(request, "404.html", context, status=404)
|
||||
|
||||
|
||||
def get_400_view(request: HttpRequest, exception=None):
|
||||
""" Returns a 400 handling view
|
||||
|
||||
Args:
|
||||
request ():
|
||||
exception ():
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
context = BaseContext.context
|
||||
return render(request, "400.html", context, status=400)
|
||||
|
||||
|
||||
def get_500_view(request: HttpRequest):
|
||||
""" Returns a 404 handling view
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
|
||||
Created on: 19.08.22
|
||||
|
||||
"""
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.gis.geos import MultiPolygon
|
||||
from django.http import HttpResponse, HttpRequest
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
@@ -24,5 +24,13 @@ class LogoutView(View):
|
||||
Returns:
|
||||
A redirect
|
||||
"""
|
||||
user = request.user
|
||||
try:
|
||||
oauth_token = user.oauth_token
|
||||
if oauth_token:
|
||||
oauth_token.revoke()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
logout(request)
|
||||
return redirect(SSO_SERVER_BASE)
|
||||
|
||||
@@ -9,15 +9,16 @@ import json
|
||||
from json import JSONDecodeError
|
||||
|
||||
import requests
|
||||
import urllib3.util
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import JsonResponse, HttpRequest
|
||||
from django.http import JsonResponse, HttpRequest, HttpResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.http import urlencode
|
||||
from django.views import View
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from requests.auth import HTTPDigestAuth
|
||||
|
||||
from konova.sub_settings.lanis_settings import MAP_PROXY_HOST_WHITELIST
|
||||
from konova.sub_settings.proxy_settings import PROXIES, GEOPORTAL_RLP_USER, GEOPORTAL_RLP_PASSWORD
|
||||
|
||||
|
||||
@@ -32,6 +33,13 @@ class BaseClientProxyView(View):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def _check_with_whitelist(self, url):
|
||||
parsed_url = urllib3.util.parse_url(url)
|
||||
parsed_url_host = parsed_url.host
|
||||
whitelist = set(MAP_PROXY_HOST_WHITELIST)
|
||||
is_allowed = parsed_url_host in whitelist
|
||||
return is_allowed
|
||||
|
||||
def perform_url_call(self, url, headers={}, auth=None):
|
||||
""" Generic proxied call
|
||||
|
||||
@@ -51,7 +59,10 @@ class BaseClientProxyView(View):
|
||||
)
|
||||
content = response.content
|
||||
if isinstance(content, bytes):
|
||||
try:
|
||||
content = content.decode("utf-8")
|
||||
except UnicodeDecodeError:
|
||||
content = f"Can not decode content of {url}"
|
||||
return content, response.status_code
|
||||
|
||||
|
||||
@@ -59,25 +70,13 @@ class ClientProxyParcelSearch(BaseClientProxyView):
|
||||
|
||||
def get(self, request: HttpRequest):
|
||||
url = request.META.get("QUERY_STRING")
|
||||
content, response_code = self.perform_url_call(url)
|
||||
try:
|
||||
body = json.loads(content)
|
||||
except JSONDecodeError as e:
|
||||
body = {
|
||||
"totalResultsCount": -1,
|
||||
"geonames": [
|
||||
{
|
||||
"title": _("The external service is currently unavailable.<br>Please try again in a few moments...")
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
if response_code != 200:
|
||||
return JsonResponse({
|
||||
"status_code": response_code,
|
||||
"content": body,
|
||||
})
|
||||
return JsonResponse(body)
|
||||
is_url_allowed = self._check_with_whitelist(url)
|
||||
if not is_url_allowed:
|
||||
raise PermissionError(f"Proxied url '{url}' is not allowed!")
|
||||
|
||||
content, response_code = self.perform_url_call(url)
|
||||
return HttpResponse(content)
|
||||
|
||||
|
||||
class ClientProxyParcelWFS(BaseClientProxyView):
|
||||
|
||||
@@ -115,10 +115,10 @@ class OAuthCallbackView(View):
|
||||
if status_code_invalid:
|
||||
raise RuntimeError(f"OAuth access token could not be fetched: {access_code_response.text}")
|
||||
|
||||
oauth_access_token = OAuthToken.from_access_token_response(access_code_response_body, received_on)
|
||||
oauth_access_token.save()
|
||||
user = oauth_access_token.update_and_get_user()
|
||||
user.oauth_replace_token(oauth_access_token)
|
||||
oauth_token = OAuthToken.from_access_token_response(access_code_response_body, received_on)
|
||||
oauth_token.save()
|
||||
user = oauth_token.update_and_get_user()
|
||||
user.oauth_replace_token(oauth_token)
|
||||
|
||||
login(request, user)
|
||||
return redirect("home")
|
||||
|
||||
Binary file not shown.
@@ -29,6 +29,7 @@
|
||||
#: konova/filters/mixins/office.py:25 konova/filters/mixins/office.py:56
|
||||
#: konova/filters/mixins/office.py:57 konova/filters/mixins/record.py:23
|
||||
#: konova/filters/mixins/self_created.py:24 konova/filters/mixins/share.py:23
|
||||
#: konova/filters/mixins/user_log.py:17 konova/filters/mixins/user_log.py:18
|
||||
#: konova/forms/geometry_form.py:32 konova/forms/modals/document_form.py:26
|
||||
#: konova/forms/modals/document_form.py:36
|
||||
#: konova/forms/modals/document_form.py:50
|
||||
@@ -37,13 +38,14 @@
|
||||
#: konova/forms/modals/remove_form.py:23
|
||||
#: konova/forms/modals/resubmission_form.py:22
|
||||
#: konova/forms/modals/resubmission_form.py:38 konova/forms/remove_form.py:25
|
||||
#: konova/tests/unit/test_forms.py:59 user/forms/user.py:39
|
||||
#: konova/tests/unit/test_forms.py:59 user/forms/modals/api_token.py:17
|
||||
#: user/forms/user.py:39
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-02-16 09:49+0100\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"
|
||||
@@ -259,7 +261,7 @@ msgstr ""
|
||||
|
||||
#: analysis/templates/analysis/reports/includes/eco_account/deductions.html:14
|
||||
#: analysis/templates/analysis/reports/includes/eco_account/deductions.html:16
|
||||
#: compensation/forms/modals/state.py:58
|
||||
#: compensation/forms/modals/state.py:59
|
||||
#: compensation/templates/compensation/detail/compensation/includes/states-after.html:36
|
||||
#: compensation/templates/compensation/detail/compensation/includes/states-before.html:36
|
||||
#: compensation/templates/compensation/detail/eco_account/includes/states-after.html:36
|
||||
@@ -372,7 +374,6 @@ msgid "Identifier"
|
||||
msgstr "Kennung"
|
||||
|
||||
#: compensation/forms/compensation.py:33 intervention/forms/intervention.py:33
|
||||
#: user/forms/user.py:77
|
||||
msgid "Generated automatically - not editable"
|
||||
msgstr "Automatisch generiert - nicht bearbeitbar"
|
||||
|
||||
@@ -447,7 +448,7 @@ msgid "Select the intervention for which this compensation compensates"
|
||||
msgstr "Wählen Sie den Eingriff, für den diese Kompensation bestimmt ist"
|
||||
|
||||
#: compensation/forms/compensation.py:114
|
||||
#: compensation/views/compensation/compensation.py:119
|
||||
#: compensation/views/compensation/compensation.py:120
|
||||
msgid "New compensation"
|
||||
msgstr "Neue Kompensation"
|
||||
|
||||
@@ -474,7 +475,7 @@ msgid "When did the parties agree on this?"
|
||||
msgstr "Wann wurde dieses Ökokonto offiziell vereinbart?"
|
||||
|
||||
#: compensation/forms/eco_account.py:72
|
||||
#: compensation/views/eco_account/eco_account.py:100
|
||||
#: compensation/views/eco_account/eco_account.py:101
|
||||
msgid "New Eco-Account"
|
||||
msgstr "Neues Ökokonto"
|
||||
|
||||
@@ -696,46 +697,46 @@ msgid "If there is no date you can enter, please explain why."
|
||||
msgstr "Falls Sie kein Datum angeben können, erklären Sie bitte weshalb."
|
||||
|
||||
#: compensation/forms/modals/payment.py:108
|
||||
#: intervention/templates/intervention/detail/includes/payments.html:59
|
||||
#: intervention/templates/intervention/detail/includes/payments.html:67
|
||||
msgid "Edit payment"
|
||||
msgstr "Zahlung bearbeiten"
|
||||
|
||||
#: compensation/forms/modals/state.py:32
|
||||
#: compensation/forms/modals/state.py:33
|
||||
msgid "Biotope Type"
|
||||
msgstr "Biotoptyp"
|
||||
|
||||
#: compensation/forms/modals/state.py:35
|
||||
#: compensation/forms/modals/state.py:36
|
||||
msgid "Select the biotope type"
|
||||
msgstr "Biotoptyp wählen"
|
||||
|
||||
#: compensation/forms/modals/state.py:39 compensation/forms/modals/state.py:51
|
||||
#: compensation/forms/modals/state.py:40 compensation/forms/modals/state.py:52
|
||||
msgid "Biotope additional type"
|
||||
msgstr "Zusatzbezeichnung"
|
||||
|
||||
#: compensation/forms/modals/state.py:42
|
||||
#: compensation/forms/modals/state.py:43
|
||||
msgid "Select an additional biotope type"
|
||||
msgstr "Zusatzbezeichnung wählen"
|
||||
|
||||
#: compensation/forms/modals/state.py:61
|
||||
#: compensation/forms/modals/state.py:62
|
||||
#: intervention/forms/modals/deduction.py:49
|
||||
msgid "in m²"
|
||||
msgstr ""
|
||||
|
||||
#: compensation/forms/modals/state.py:72
|
||||
#: compensation/forms/modals/state.py:73
|
||||
#: compensation/tests/compensation/unit/test_forms.py:175
|
||||
msgid "New state"
|
||||
msgstr "Neuer Zustand"
|
||||
|
||||
#: compensation/forms/modals/state.py:73
|
||||
#: compensation/forms/modals/state.py:74
|
||||
#: compensation/tests/compensation/unit/test_forms.py:176
|
||||
msgid "Insert data for the new state"
|
||||
msgstr "Geben Sie die Daten des neuen Zustandes ein"
|
||||
|
||||
#: compensation/forms/modals/state.py:90 konova/forms/modals/base_form.py:32
|
||||
#: compensation/forms/modals/state.py:91 konova/forms/modals/base_form.py:32
|
||||
msgid "Object removed"
|
||||
msgstr "Objekt entfernt"
|
||||
|
||||
#: compensation/forms/modals/state.py:145
|
||||
#: compensation/forms/modals/state.py:146
|
||||
#: compensation/templates/compensation/detail/compensation/includes/states-after.html:62
|
||||
#: compensation/templates/compensation/detail/compensation/includes/states-before.html:62
|
||||
#: compensation/templates/compensation/detail/eco_account/includes/states-after.html:62
|
||||
@@ -1287,44 +1288,44 @@ msgstr ""
|
||||
msgid "Responsible data"
|
||||
msgstr "Daten zu den verantwortlichen Stellen"
|
||||
|
||||
#: compensation/views/compensation/compensation.py:57
|
||||
#: compensation/views/compensation/compensation.py:58
|
||||
msgid "Compensations - Overview"
|
||||
msgstr "Kompensationen - Übersicht"
|
||||
|
||||
#: compensation/views/compensation/compensation.py:180
|
||||
#: compensation/views/compensation/compensation.py:181
|
||||
#: konova/utils/message_templates.py:40
|
||||
msgid "Compensation {} edited"
|
||||
msgstr "Kompensation {} bearbeitet"
|
||||
|
||||
#: compensation/views/compensation/compensation.py:195
|
||||
#: compensation/views/eco_account/eco_account.py:172 ema/views/ema.py:230
|
||||
#: intervention/views/intervention.py:251
|
||||
#: compensation/views/compensation/compensation.py:196
|
||||
#: 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:34
|
||||
#: compensation/views/eco_account/report.py:34 ema/views/report.py:34
|
||||
#: intervention/views/report.py:37
|
||||
#: compensation/views/compensation/report.py:35
|
||||
#: compensation/views/eco_account/report.py:36 ema/views/report.py:35
|
||||
#: intervention/views/report.py:35
|
||||
msgid "Report {}"
|
||||
msgstr "Bericht {}"
|
||||
|
||||
#: compensation/views/eco_account/eco_account.py:52
|
||||
#: compensation/views/eco_account/eco_account.py:53
|
||||
msgid "Eco-account - Overview"
|
||||
msgstr "Ökokonten - Übersicht"
|
||||
|
||||
#: compensation/views/eco_account/eco_account.py:85
|
||||
#: compensation/views/eco_account/eco_account.py:86
|
||||
msgid "Eco-Account {} added"
|
||||
msgstr "Ökokonto {} hinzugefügt"
|
||||
|
||||
#: compensation/views/eco_account/eco_account.py:157
|
||||
#: compensation/views/eco_account/eco_account.py:158
|
||||
msgid "Eco-Account {} edited"
|
||||
msgstr "Ökokonto {} bearbeitet"
|
||||
|
||||
#: compensation/views/eco_account/eco_account.py:286
|
||||
#: compensation/views/eco_account/eco_account.py:288
|
||||
msgid "Eco-account removed"
|
||||
msgstr "Ökokonto entfernt"
|
||||
|
||||
#: ema/forms.py:42 ema/tests/unit/test_forms.py:27 ema/views/ema.py:101
|
||||
#: ema/forms.py:42 ema/tests/unit/test_forms.py:27 ema/views/ema.py:108
|
||||
msgid "New EMA"
|
||||
msgstr "Neue EMA hinzufügen"
|
||||
|
||||
@@ -1352,19 +1353,19 @@ msgstr ""
|
||||
msgid "Payment funded compensation"
|
||||
msgstr "Ersatzzahlungsmaßnahme"
|
||||
|
||||
#: ema/views/ema.py:52
|
||||
#: ema/views/ema.py:53
|
||||
msgid "EMAs - Overview"
|
||||
msgstr "EMAs - Übersicht"
|
||||
|
||||
#: ema/views/ema.py:85
|
||||
#: ema/views/ema.py:86
|
||||
msgid "EMA {} added"
|
||||
msgstr "EMA {} hinzugefügt"
|
||||
|
||||
#: ema/views/ema.py:215
|
||||
#: ema/views/ema.py:223
|
||||
msgid "EMA {} edited"
|
||||
msgstr "EMA {} bearbeitet"
|
||||
|
||||
#: ema/views/ema.py:254
|
||||
#: ema/views/ema.py:262
|
||||
msgid "EMA removed"
|
||||
msgstr "EMA entfernt"
|
||||
|
||||
@@ -1428,7 +1429,7 @@ msgstr "Datum Bestandskraft bzw. Rechtskraft"
|
||||
|
||||
#: intervention/forms/intervention.py:216
|
||||
#: intervention/tests/unit/test_forms.py:36
|
||||
#: intervention/views/intervention.py:104
|
||||
#: intervention/views/intervention.py:105
|
||||
msgid "New intervention"
|
||||
msgstr "Neuer Eingriff"
|
||||
|
||||
@@ -1597,7 +1598,12 @@ msgctxt "money"
|
||||
msgid "Amount"
|
||||
msgstr "Betrag"
|
||||
|
||||
#: intervention/templates/intervention/detail/includes/payments.html:62
|
||||
#: intervention/templates/intervention/detail/includes/payments.html:61
|
||||
#: konova/utils/message_templates.py:25
|
||||
msgid "This data is not shared with you"
|
||||
msgstr "Diese Daten sind für Sie nicht freigegeben"
|
||||
|
||||
#: intervention/templates/intervention/detail/includes/payments.html:70
|
||||
msgid "Remove payment"
|
||||
msgstr "Zahlung entfernen"
|
||||
|
||||
@@ -1659,19 +1665,19 @@ msgstr ""
|
||||
msgid "Check performed"
|
||||
msgstr "Prüfung durchgeführt"
|
||||
|
||||
#: intervention/views/intervention.py:56
|
||||
#: intervention/views/intervention.py:57
|
||||
msgid "Interventions - Overview"
|
||||
msgstr "Eingriffe - Übersicht"
|
||||
|
||||
#: intervention/views/intervention.py:89
|
||||
#: intervention/views/intervention.py:90
|
||||
msgid "Intervention {} added"
|
||||
msgstr "Eingriff {} hinzugefügt"
|
||||
|
||||
#: intervention/views/intervention.py:234
|
||||
#: intervention/views/intervention.py:236
|
||||
msgid "Intervention {} edited"
|
||||
msgstr "Eingriff {} bearbeitet"
|
||||
|
||||
#: intervention/views/intervention.py:276
|
||||
#: intervention/views/intervention.py:278
|
||||
msgid "{} removed"
|
||||
msgstr "{} entfernt"
|
||||
|
||||
@@ -1781,6 +1787,16 @@ msgstr ""
|
||||
"Wenn aktiviert werden auch Einträge angezeigt, die nicht für Sie freigegeben "
|
||||
"sind"
|
||||
|
||||
#: konova/filters/mixins/user_log.py:21
|
||||
msgid "Logged user"
|
||||
msgstr "Bearbeitender Nutzer"
|
||||
|
||||
#: konova/filters/mixins/user_log.py:22
|
||||
msgid ""
|
||||
"Search for entries where this person has been participated according to log "
|
||||
"history"
|
||||
msgstr "Sucht nach Einträgen, an denen diese Person gearbeitet hat"
|
||||
|
||||
#: konova/forms/base_form.py:23 templates/form/collapsable/form.html:62
|
||||
msgid "Save"
|
||||
msgstr "Speichern"
|
||||
@@ -1799,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?"
|
||||
@@ -1841,6 +1853,7 @@ msgstr ""
|
||||
"Ich, {} {}, bestätige, dass diese Daten wieder entzeichnet werden müssen."
|
||||
|
||||
#: konova/forms/modals/remove_form.py:22 konova/forms/remove_form.py:24
|
||||
#: user/forms/modals/api_token.py:16
|
||||
msgid "Confirm"
|
||||
msgstr "Bestätige"
|
||||
|
||||
@@ -1911,11 +1924,11 @@ msgstr "Kontrolle am"
|
||||
msgid "Other"
|
||||
msgstr "Sonstige"
|
||||
|
||||
#: konova/sub_settings/django_settings.py:166
|
||||
#: konova/sub_settings/django_settings.py:156
|
||||
msgid "German"
|
||||
msgstr ""
|
||||
|
||||
#: konova/sub_settings/django_settings.py:167
|
||||
#: konova/sub_settings/django_settings.py:157
|
||||
msgid "English"
|
||||
msgstr ""
|
||||
|
||||
@@ -2091,10 +2104,6 @@ msgstr ""
|
||||
"Eintrag ist verzeichnet. Um Daten zu bearbeiten, muss der Eintrag erst "
|
||||
"entzeichnet werden."
|
||||
|
||||
#: konova/utils/message_templates.py:25
|
||||
msgid "This data is not shared with you"
|
||||
msgstr "Diese Daten sind für Sie nicht freigegeben"
|
||||
|
||||
#: konova/utils/message_templates.py:26
|
||||
msgid ""
|
||||
"Remember: This data has not been shared with you, yet. This means you can "
|
||||
@@ -2253,34 +2262,35 @@ 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/messenger.py:70
|
||||
msgid "{} checked"
|
||||
msgstr "{} geprüft"
|
||||
|
||||
#: konova/utils/messenger.py:72
|
||||
msgid "<a href=\"{}\">Check it out</a>"
|
||||
msgstr "<a href=\"{}\">Schauen Sie rein</a>"
|
||||
|
||||
#: konova/utils/messenger.py:73
|
||||
msgid "{} has been checked successfully by user {}! {}"
|
||||
msgstr "{} wurde erfolgreich vom Nutzer {} geprüft! {}"
|
||||
#: konova/utils/message_templates.py:97
|
||||
msgid "New token generated. Administrators need to validate."
|
||||
msgstr "Neuer Token generiert. Administratoren sind informiert."
|
||||
|
||||
#: konova/utils/quality.py:32
|
||||
msgid "missing"
|
||||
@@ -2308,14 +2318,6 @@ msgstr "Home"
|
||||
msgid "Log"
|
||||
msgstr "Log"
|
||||
|
||||
#: konova/views/map_proxy.py:70
|
||||
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"
|
||||
@@ -2372,6 +2374,20 @@ msgstr "Alle"
|
||||
msgid "News"
|
||||
msgstr "Neuigkeiten"
|
||||
|
||||
#: templates/400.html:12
|
||||
msgid "Request was invalid"
|
||||
msgstr "Anfrage fehlerhaft"
|
||||
|
||||
#: 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: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, ...)."
|
||||
|
||||
#: templates/404.html:7
|
||||
msgid "Not found"
|
||||
msgstr "Nicht gefunden"
|
||||
@@ -2384,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 "
|
||||
@@ -2817,11 +2833,15 @@ msgstr "Mehr"
|
||||
msgid "Reports"
|
||||
msgstr "Berichte"
|
||||
|
||||
#: templates/navbars/navbar.html:56 user/templates/user/index.html:31
|
||||
#: templates/navbars/navbar.html:57
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: templates/navbars/navbar.html:59 user/templates/user/index.html:31
|
||||
msgid "Settings"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
#: templates/navbars/navbar.html:57
|
||||
#: templates/navbars/navbar.html:60
|
||||
msgid "Logout"
|
||||
msgstr "Abmelden"
|
||||
|
||||
@@ -2854,6 +2874,22 @@ msgstr ""
|
||||
"Falls die Geometrie nicht leer ist, werden die Flurstücke aktuell berechnet. "
|
||||
"Bitte laden Sie diese Seite in ein paar Augenblicken erneut..."
|
||||
|
||||
#: user/forms/modals/api_token.py:25
|
||||
msgid "Generate API Token"
|
||||
msgstr "API Token generieren"
|
||||
|
||||
#: user/forms/modals/api_token.py:29
|
||||
msgid ""
|
||||
"You are about to create a new API token. The existing one will not be usable "
|
||||
"afterwards."
|
||||
msgstr ""
|
||||
"Wenn Sie fortfahren, generieren Sie einen neuen API Token. Ihren "
|
||||
"existierenden werden Sie dann nicht länger nutzen können."
|
||||
|
||||
#: user/forms/modals/api_token.py:31
|
||||
msgid "A new token needs to be validated by an administrator!"
|
||||
msgstr "Neue Tokens müssen durch Administratoren freigeschaltet werden!"
|
||||
|
||||
#: user/forms/modals/team.py:20 user/forms/modals/team.py:24
|
||||
#: user/forms/team.py:17 user/forms/team.py:22
|
||||
msgid "Team name"
|
||||
@@ -2876,11 +2912,11 @@ msgstr ""
|
||||
"Mehrfachauswahl möglich - Sie können nur Nutzer wählen, die noch nicht "
|
||||
"Mitglieder dieses Teams sind. Geben Sie den ganzen Nutzernamen an."
|
||||
|
||||
#: user/forms/modals/team.py:56 user/tests/unit/test_forms.py:31
|
||||
#: user/forms/modals/team.py:56 user/tests/unit/test_forms.py:30
|
||||
msgid "Create new team"
|
||||
msgstr "Neues Team anlegen"
|
||||
|
||||
#: user/forms/modals/team.py:57 user/tests/unit/test_forms.py:32
|
||||
#: user/forms/modals/team.py:57 user/tests/unit/test_forms.py:31
|
||||
msgid ""
|
||||
"You will become the administrator for this group by default. You do not need "
|
||||
"to add yourself to the list of members."
|
||||
@@ -2909,11 +2945,11 @@ msgid "There must be at least one admin on this team."
|
||||
msgstr "Es muss mindestens einen Administrator für das Team geben."
|
||||
|
||||
#: user/forms/modals/team.py:160 user/templates/user/team/index.html:60
|
||||
#: user/tests/unit/test_forms.py:88
|
||||
#: user/tests/unit/test_forms.py:87
|
||||
msgid "Edit team"
|
||||
msgstr "Team bearbeiten"
|
||||
|
||||
#: user/forms/modals/team.py:187 user/tests/unit/test_forms.py:165
|
||||
#: user/forms/modals/team.py:187 user/tests/unit/test_forms.py:164
|
||||
msgid ""
|
||||
"ATTENTION!\n"
|
||||
"\n"
|
||||
@@ -2930,7 +2966,7 @@ msgstr ""
|
||||
"Sind Sie sicher, dass Sie dieses Team löschen möchten?"
|
||||
|
||||
#: user/forms/modals/team.py:197 user/templates/user/team/index.html:56
|
||||
#: user/tests/unit/test_forms.py:198
|
||||
#: user/tests/unit/test_forms.py:197
|
||||
msgid "Leave team"
|
||||
msgstr "Team verlassen"
|
||||
|
||||
@@ -2962,22 +2998,10 @@ msgstr "Benachrichtigungen"
|
||||
msgid "Select the situations when you want to receive a notification"
|
||||
msgstr "Wann wollen Sie per E-Mail benachrichtigt werden?"
|
||||
|
||||
#: user/forms/user.py:38 user/tests/unit/test_forms.py:234
|
||||
#: user/forms/user.py:38 user/tests/unit/test_forms.py:233
|
||||
msgid "Edit notifications"
|
||||
msgstr "Benachrichtigungen bearbeiten"
|
||||
|
||||
#: user/forms/user.py:73
|
||||
msgid "Token"
|
||||
msgstr ""
|
||||
|
||||
#: user/forms/user.py:88 user/tests/unit/test_forms.py:260
|
||||
msgid "Create new token"
|
||||
msgstr "Neuen Token generieren"
|
||||
|
||||
#: user/forms/user.py:89 user/tests/unit/test_forms.py:261
|
||||
msgid "A new token needs to be validated by an administrator!"
|
||||
msgstr "Neue Tokens müssen durch Administratoren freigeschaltet werden!"
|
||||
|
||||
#: user/models/user_action.py:23
|
||||
msgid "Unrecorded"
|
||||
msgstr "Entzeichnet"
|
||||
@@ -3032,7 +3056,7 @@ msgid "Manage teams"
|
||||
msgstr ""
|
||||
|
||||
#: user/templates/user/index.html:53 user/templates/user/team/index.html:19
|
||||
#: user/views.py:171
|
||||
#: user/views/views.py:135
|
||||
msgid "Teams"
|
||||
msgstr ""
|
||||
|
||||
@@ -3068,270 +3092,58 @@ msgstr "API Einstellungen"
|
||||
msgid "Current token"
|
||||
msgstr "Aktueller Token"
|
||||
|
||||
#: user/templates/user/token.html:14
|
||||
#: user/templates/user/token.html:15
|
||||
msgid "Create new token"
|
||||
msgstr "Neuen Token generieren"
|
||||
|
||||
#: user/templates/user/token.html:23
|
||||
msgid "Authenticated by admins"
|
||||
msgstr "Von Admin freigeschaltet"
|
||||
|
||||
#: user/templates/user/token.html:18
|
||||
#: user/templates/user/token.html:27
|
||||
msgid "Token has been verified and can be used"
|
||||
msgstr "Token wurde freigeschaltet und kann verwendet werden"
|
||||
|
||||
#: user/templates/user/token.html:20
|
||||
#: user/templates/user/token.html:29
|
||||
msgid "Token waiting for verification"
|
||||
msgstr "Token noch nicht freigeschaltet"
|
||||
|
||||
#: user/templates/user/token.html:24
|
||||
#: user/templates/user/token.html:33
|
||||
msgid "Valid until"
|
||||
msgstr "Läuft ab am"
|
||||
|
||||
#: user/views.py:35
|
||||
msgid "User settings"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
#: user/views.py:61
|
||||
msgid "Notifications edited"
|
||||
msgstr "Benachrichtigungen bearbeitet"
|
||||
|
||||
#: user/views.py:73
|
||||
msgid "User notifications"
|
||||
msgstr "Benachrichtigungen"
|
||||
|
||||
#: user/views.py:96
|
||||
msgid "New token generated. Administrators need to validate."
|
||||
msgstr "Neuer Token generiert. Administratoren sind informiert."
|
||||
|
||||
#: user/views.py:107
|
||||
#: user/views/api_token.py:34
|
||||
msgid "User API token"
|
||||
msgstr "API Nutzer Token"
|
||||
|
||||
#: user/views.py:183
|
||||
#: user/views/views.py:33
|
||||
msgid "User settings"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
#: user/views/views.py:59
|
||||
msgid "Notifications edited"
|
||||
msgstr "Benachrichtigungen bearbeitet"
|
||||
|
||||
#: user/views/views.py:71
|
||||
msgid "User notifications"
|
||||
msgstr "Benachrichtigungen"
|
||||
|
||||
#: user/views/views.py:147
|
||||
msgid "New team added"
|
||||
msgstr "Neues Team hinzugefügt"
|
||||
|
||||
#: user/views.py:198
|
||||
#: user/views/views.py:162
|
||||
msgid "Team edited"
|
||||
msgstr "Team bearbeitet"
|
||||
|
||||
#: user/views.py:213
|
||||
#: user/views/views.py:177
|
||||
msgid "Team removed"
|
||||
msgstr "Team gelöscht"
|
||||
|
||||
#: user/views.py:228
|
||||
#: user/views/views.py:192
|
||||
msgid "You are not a member of this team"
|
||||
msgstr "Sie sind kein Mitglied dieses Teams"
|
||||
|
||||
#: user/views.py:235
|
||||
#: user/views/views.py:199
|
||||
msgid "Left Team"
|
||||
msgstr "Team verlassen"
|
||||
|
||||
#~ msgid "close"
|
||||
#~ msgstr "Schließen"
|
||||
|
||||
#~ msgid "Options"
|
||||
#~ msgstr "Optionen"
|
||||
|
||||
#~ msgid "Commands"
|
||||
#~ msgstr "Befehle"
|
||||
|
||||
#~ msgid "Missing command."
|
||||
#~ msgstr "Befehl fehlt"
|
||||
|
||||
#~ msgid "Missing argument"
|
||||
#~ msgstr "Argument fehlt"
|
||||
|
||||
#~ msgid "Missing option"
|
||||
#~ msgstr "Option fehlt"
|
||||
|
||||
#~ msgid "Missing parameter"
|
||||
#~ msgstr "Parameter fehlt"
|
||||
|
||||
#~ msgid "Messages"
|
||||
#~ msgstr "Nachrichten"
|
||||
|
||||
#~ msgid "This field is required."
|
||||
#~ msgstr "Pflichtfeld"
|
||||
|
||||
#~ msgid "Monday"
|
||||
#~ msgstr "Montag"
|
||||
|
||||
#~ msgid "Tuesday"
|
||||
#~ msgstr "Dienstag"
|
||||
|
||||
#~ msgid "Wednesday"
|
||||
#~ msgstr "Mittwoch"
|
||||
|
||||
#~ msgid "Thursday"
|
||||
#~ msgstr "Donnerstag"
|
||||
|
||||
#~ msgid "Friday"
|
||||
#~ msgstr "Freitag"
|
||||
|
||||
#~ msgid "Saturday"
|
||||
#~ msgstr "Samstag"
|
||||
|
||||
#~ msgid "Sunday"
|
||||
#~ msgstr "Sonntag"
|
||||
|
||||
#~ msgid "Mon"
|
||||
#~ msgstr "Mo"
|
||||
|
||||
#~ msgid "Tue"
|
||||
#~ msgstr "Di"
|
||||
|
||||
#~ msgid "Wed"
|
||||
#~ msgstr "Mi"
|
||||
|
||||
#~ msgid "Thu"
|
||||
#~ msgstr "Do"
|
||||
|
||||
#~ msgid "Fri"
|
||||
#~ msgstr "Fr"
|
||||
|
||||
#~ msgid "Sat"
|
||||
#~ msgstr "Sa"
|
||||
|
||||
#~ msgid "Sun"
|
||||
#~ msgstr "So"
|
||||
|
||||
#~ msgid "January"
|
||||
#~ msgstr "Januar"
|
||||
|
||||
#~ msgid "February"
|
||||
#~ msgstr "Februar"
|
||||
|
||||
#~ msgid "March"
|
||||
#~ msgstr "März"
|
||||
|
||||
#~ msgid "May"
|
||||
#~ msgstr "Mai"
|
||||
|
||||
#~ msgid "June"
|
||||
#~ msgstr "Juni"
|
||||
|
||||
#~ msgid "July"
|
||||
#~ msgstr "Juli"
|
||||
|
||||
#~ msgid "October"
|
||||
#~ msgstr "Oktober"
|
||||
|
||||
#~ msgid "December"
|
||||
#~ msgstr "Dezember"
|
||||
|
||||
#~ msgid "mar"
|
||||
#~ msgstr "mär"
|
||||
|
||||
#~ msgid "may"
|
||||
#~ msgstr "mai"
|
||||
|
||||
#~ msgid "oct"
|
||||
#~ msgstr "okt"
|
||||
|
||||
#~ msgid "dec"
|
||||
#~ msgstr "dez"
|
||||
|
||||
#~ msgctxt "abbrev. month"
|
||||
#~ msgid "March"
|
||||
#~ msgstr "Mär"
|
||||
|
||||
#~ msgctxt "abbrev. month"
|
||||
#~ msgid "May"
|
||||
#~ msgstr "Mai"
|
||||
|
||||
#~ msgctxt "abbrev. month"
|
||||
#~ msgid "June"
|
||||
#~ msgstr "Juni"
|
||||
|
||||
#~ msgctxt "abbrev. month"
|
||||
#~ msgid "July"
|
||||
#~ msgstr "Juli"
|
||||
|
||||
#~ msgctxt "abbrev. month"
|
||||
#~ msgid "Oct."
|
||||
#~ msgstr "Okt."
|
||||
|
||||
#~ msgctxt "abbrev. month"
|
||||
#~ msgid "Dec."
|
||||
#~ msgstr "Dez."
|
||||
|
||||
#~ msgctxt "alt. month"
|
||||
#~ msgid "January"
|
||||
#~ msgstr "Januar"
|
||||
|
||||
#~ msgctxt "alt. month"
|
||||
#~ msgid "February"
|
||||
#~ msgstr "Februar"
|
||||
|
||||
#~ msgctxt "alt. month"
|
||||
#~ msgid "March"
|
||||
#~ msgstr "März"
|
||||
|
||||
#~ msgctxt "alt. month"
|
||||
#~ msgid "May"
|
||||
#~ msgstr "Mai"
|
||||
|
||||
#~ msgctxt "alt. month"
|
||||
#~ msgid "June"
|
||||
#~ msgstr "Juni"
|
||||
|
||||
#~ msgctxt "alt. month"
|
||||
#~ msgid "July"
|
||||
#~ msgstr "Juli"
|
||||
|
||||
#~ msgctxt "alt. month"
|
||||
#~ msgid "October"
|
||||
#~ msgstr "Oktober"
|
||||
|
||||
#~ msgctxt "alt. month"
|
||||
#~ msgid "December"
|
||||
#~ msgstr "Dezember"
|
||||
|
||||
#~ msgid "or"
|
||||
#~ msgstr "oder"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Deductable surface can not be larger than existing surfaces in after "
|
||||
#~ "states"
|
||||
#~ msgstr ""
|
||||
#~ "Die abbuchbare Fläche darf die Gesamtfläche der Zielzustände nicht "
|
||||
#~ "überschreiten"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Deductable surface can not be smaller than the sum of already existing "
|
||||
#~ "deductions. Please contact the responsible users for the deductions!"
|
||||
#~ msgstr ""
|
||||
#~ "Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar "
|
||||
#~ "einstellen wollen. Kontaktieren Sie die für die Abbuchungen "
|
||||
#~ "verantwortlichen Nutzer!"
|
||||
|
||||
#~ msgid "Added deadline"
|
||||
#~ msgstr "Frist/Termin hinzugefügt"
|
||||
|
||||
#~ msgid "Change default configuration for your KSP map"
|
||||
#~ msgstr "Karteneinstellungen ändern"
|
||||
|
||||
#~ msgid "Map settings"
|
||||
#~ msgstr "Karte"
|
||||
|
||||
#~ msgid "There are errors on this intervention:"
|
||||
#~ msgstr "Es liegen Fehler in diesem Eingriff vor:"
|
||||
|
||||
#~ msgid "Before"
|
||||
#~ msgstr "Vor"
|
||||
|
||||
#~ msgid "Groups"
|
||||
#~ msgstr "Gruppen"
|
||||
|
||||
#~ msgid "Show more..."
|
||||
#~ msgstr "Mehr anzeigen..."
|
||||
|
||||
#~ msgid "Kreis"
|
||||
#~ msgstr "Kreis"
|
||||
|
||||
#~ msgid "Gemarkung"
|
||||
#~ msgstr "Gemarkung"
|
||||
|
||||
#~ msgid "Loading..."
|
||||
#~ msgstr "Lade..."
|
||||
|
||||
#~ msgid "Who handles the eco-account"
|
||||
#~ msgstr "Wer für die Herrichtung des Ökokontos verantwortlich ist"
|
||||
|
||||
@@ -1,65 +1,63 @@
|
||||
amqp==5.2.0
|
||||
amqp==5.3.1
|
||||
asgiref==3.8.1
|
||||
async-timeout==4.0.3
|
||||
async-timeout==5.0.1
|
||||
beautifulsoup4==4.13.0b2
|
||||
billiard==4.2.0
|
||||
cached-property==1.5.2
|
||||
billiard==4.2.1
|
||||
cached-property==2.0.1
|
||||
celery==5.4.0
|
||||
certifi==2024.7.4
|
||||
cffi==1.17.0rc1
|
||||
certifi==2024.12.14
|
||||
cffi==1.17.1
|
||||
chardet==5.2.0
|
||||
charset-normalizer==3.3.2
|
||||
click==8.1.7
|
||||
charset-normalizer==3.4.0
|
||||
click==8.1.8
|
||||
click-didyoumean==0.3.1
|
||||
click-plugins==1.1.1
|
||||
click-repl==0.3.0
|
||||
coverage==7.5.4
|
||||
cryptography==42.0.8
|
||||
Deprecated==1.2.14
|
||||
Django==5.0.7
|
||||
coverage==7.6.9
|
||||
cryptography==44.0.0
|
||||
Deprecated==1.2.15
|
||||
Django==5.1.4
|
||||
django-autocomplete-light==3.11.0
|
||||
django-bootstrap-modal-forms==3.0.4
|
||||
django-bootstrap4==24.3
|
||||
django-bootstrap-modal-forms==3.0.5
|
||||
django-bootstrap4==24.4
|
||||
django-environ==0.11.2
|
||||
django-filter==24.2
|
||||
django-filter==24.3
|
||||
django-fontawesome-5==1.0.18
|
||||
django-oauth-toolkit==2.4.0
|
||||
django-simple-sso==1.2.0
|
||||
django-tables2==2.7.0
|
||||
et-xmlfile==1.1.0
|
||||
gunicorn==22.0.0
|
||||
idna==3.7
|
||||
importlib_metadata==8.0.0
|
||||
itsdangerous==0.24
|
||||
django-oauth-toolkit==3.0.1
|
||||
django-tables2==2.7.1
|
||||
et_xmlfile==2.0.0
|
||||
gunicorn==23.0.0
|
||||
idna==3.10
|
||||
importlib_metadata==8.5.0
|
||||
jwcrypto==1.5.6
|
||||
kombu==5.4.0rc1
|
||||
oauthlib==3.2.2
|
||||
openpyxl==3.2.0b1
|
||||
packaging==24.1
|
||||
packaging==24.2
|
||||
pika==1.3.2
|
||||
pillow==10.4.0
|
||||
prompt_toolkit==3.0.47
|
||||
psycopg==3.2.1
|
||||
psycopg-binary==3.2.1
|
||||
pillow==11.0.0
|
||||
prompt_toolkit==3.0.48
|
||||
psycopg==3.2.3
|
||||
psycopg-binary==3.2.3
|
||||
pycparser==2.22
|
||||
pyparsing==3.1.2
|
||||
pyparsing==3.2.0
|
||||
pypng==0.20220715.0
|
||||
pyproj==3.6.1
|
||||
pyproj==3.7.0
|
||||
python-dateutil==2.9.0.post0
|
||||
pytz==2024.1
|
||||
PyYAML==6.0.2rc1
|
||||
pytz==2024.2
|
||||
PyYAML==6.0.2
|
||||
qrcode==7.3.1
|
||||
redis==5.1.0b6
|
||||
requests<2.32.0
|
||||
requests==2.32.3
|
||||
six==1.16.0
|
||||
soupsieve==2.5
|
||||
sqlparse==0.5.0
|
||||
sqlparse==0.5.1
|
||||
typing_extensions==4.12.2
|
||||
tzdata==2024.1
|
||||
urllib3==2.2.2
|
||||
tzdata==2024.2
|
||||
urllib3==2.3.0
|
||||
vine==5.1.0
|
||||
wcwidth==0.2.13
|
||||
webservices==0.7
|
||||
wrapt==1.16.0
|
||||
xmltodict==0.13.0
|
||||
zipp==3.19.2
|
||||
xmltodict==0.14.2
|
||||
zipp==3.21.0
|
||||
|
||||
21
templates/400.html
Normal file
21
templates/400.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{% extends 'public_base.html' %}
|
||||
{% load i18n fontawesome_5 static %}
|
||||
|
||||
{% block body %}
|
||||
<div class="jumbotron">
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<img src="{% static 'images/error_imgs/croc_technician_400.png' %}" style="max-width: 150px">
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9 col-lg-9 col-xl-10">
|
||||
<h1 class="display-4">{% fa5_icon 'question-circle' %}400</h1>
|
||||
<h1 class="display-4">{% trans 'Request was invalid' %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<p class="lead">
|
||||
{% trans 'There seems to be a problem with the link you opened.' %}
|
||||
{% trans 'Make sure the URL is valid (no whitespaces, properly copied, ...).' %}
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,10 +1,17 @@
|
||||
{% extends 'public_base.html' %}
|
||||
{% load i18n fontawesome_5 %}
|
||||
{% load i18n fontawesome_5 static %}
|
||||
|
||||
{% block body %}
|
||||
<div class="jumbotron">
|
||||
<h1 class="display-4">{% fa5_icon 'fire-extinguisher' %} {% fa5_icon 'fire-alt' %} 500</h1>
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<img src="{% static 'images/error_imgs/croc_technician_500.png' %}" style="max-width: 150px">
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-9 col-lg-9 col-xl-10">
|
||||
<h1 class="display-4">{% fa5_icon 'fire-alt' %} 500</h1>
|
||||
<h1 class="display-4">{% trans 'Server Error' %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<p class="lead">
|
||||
{% trans 'Something happened. Admins have been informed. We are working on it!' %}
|
||||
|
||||
@@ -1,170 +1,304 @@
|
||||
{
|
||||
"layers":
|
||||
"modules":
|
||||
{
|
||||
"menu": true,
|
||||
"layertree": true,
|
||||
"map": true,
|
||||
"controls": true,
|
||||
"attribution": true,
|
||||
"info": true,
|
||||
"searchplace": true,
|
||||
"searchparcel": true,
|
||||
"toolbox": true,
|
||||
"import": true,
|
||||
"export": true
|
||||
},
|
||||
"menu":
|
||||
{
|
||||
"header": "",
|
||||
"items":
|
||||
[
|
||||
{ "folder": 5, "type": "WMS", "title": "KOM Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=kom_f&", "name": "kom_f" },
|
||||
{ "folder": 5, "type": "WMS", "title": "KOM Linien", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=kom_l&", "name": "kom_l" },
|
||||
{ "folder": 5, "type": "WMS", "title": "KOM Punkte", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=komon&", "name": "kom_p" },
|
||||
|
||||
{ "folder": 6, "type": "WMS", "title": "EIV Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=eiv_f&", "name": "eiv_f" },
|
||||
{ "folder": 6, "type": "WMS", "title": "EIV Linien", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=eiv_l&", "name": "eiv_l" },
|
||||
{ "folder": 6, "type": "WMS", "title": "EIV Punkte", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=eiv_p&", "name": "eiv_p" },
|
||||
|
||||
{ "folder": 7, "type": "WMS", "title": "OEK Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=oek_f&", "name": "oek_f" },
|
||||
|
||||
{ "folder": 8, "type": "WMS", "title": "EMA Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=ema_f&", "name": "ema_f" },
|
||||
|
||||
{ "folder": 9, "type": "WMS", "title": "MAE Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=mae&", "name": "mae" },
|
||||
|
||||
{ "folder": 10, "type": "WMS", "title": "Naturschutzgebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=naturschutzgebiet&", "name": "naturschutzgebiet" },
|
||||
{ "folder": 10, "type": "WMS", "title": "Naturparkzonen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=naturparkzonen&", "name": "naturparkzonen" },
|
||||
{ "folder": 10, "type": "WMS", "title": "Landschaftsschutzgebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=landschaftsschutzgebiet&", "name": "landschaftsschutzgebiet" },
|
||||
{ "folder": 10, "type": "WMS", "title": "Vogelschutzgebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=vogelschutzgebiet&", "name": "vogelschutzgebiet" },
|
||||
{ "folder": 10, "type": "WMS", "title": "FFH Gebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=ffh&", "name": "ffh" },
|
||||
|
||||
{ "folder": 11, "type": "WMS", "title": "Nationalpark Zonen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=nationalpark_zonen&", "name": "nationalpark_zonen" },
|
||||
{ "folder": 11, "type": "WMS", "title": "Nationalpark Grenzen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=nationalpark_grenze&", "name": "nationalpark_grenze" },
|
||||
|
||||
{ "folder": 12, "type": "WMS", "title": "Naturräume Grenzen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=natraum_lkompvo_grenzen&", "name": "natraum_lkompvo_grenzen" },
|
||||
{ "folder": 12, "type": "WMS", "title": "Naturräume Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=natraum_lkompvo&", "name": "natraum_lkompvo" },
|
||||
|
||||
{ "folder": 1, "type": "WMS", "title": "Lagebezeichnungen", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "Lagebezeichnungen" },
|
||||
{ "folder": 1, "type": "WMS", "title": "Flurstücke (WMS)", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "Flurstueck", "active": true},
|
||||
{ "folder": 1, "type": "WFS", "title": "Flurstücke (WFS; ab hoher Zoomstufe)", "url": "/client/proxy/wfs?", "name": "ave:Flurstueck", "minZoom": 17},
|
||||
{ "folder": 1, "type": "WMS", "title": "Gebäude / Bauwerke", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "GebaeudeBauwerke" },
|
||||
{ "folder": 1, "type": "WMS", "title": "Nutzung", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "Nutzung" },
|
||||
|
||||
{ "folder": 2, "type": "WMS", "title": "Landkreise", "url": "http://geo5.service24.rlp.de/wms/verwaltungsgrenzen_rp.fcgi?", "name": "Landkreise" },
|
||||
{ "folder": 2, "type": "WMS", "title": "Verbandsgemeinden", "url": "http://geo5.service24.rlp.de/wms/verwaltungsgrenzen_rp.fcgi?", "name": "Verbandsgemeinden" },
|
||||
{ "folder": 2, "type": "WMS", "title": "Gemeinden", "url": "http://geo5.service24.rlp.de/wms/verwaltungsgrenzen_rp.fcgi?", "name": "Gemeinden" },
|
||||
|
||||
{ "folder": 15, "type": "WMS", "order": -1, "title": "farbig", "attribution": "LVermGeo", "url": "https://maps.service24.rlp.de/gisserver/services/RP/RP_WebAtlasRP/MapServer/WmsServer?", "name": "RP_WebAtlasRP", "active": true},
|
||||
{ "folder": 15, "type": "WMS", "title": "grau", "attribution": "LVermGeo", "url": "https://maps.service24.rlp.de/gisserver/services/RP/RP_ETRS_Gt/MapServer/WmsServer?", "name": "0", "active": false },
|
||||
{ "folder": 0, "type": "WMS", "title": "Luftbilder", "attribution": "LVermGeo", "url": "http://geo4.service24.rlp.de/wms/dop_basis.fcgi?", "name": "rp_dop", "active": false },
|
||||
{ "folder": 14, "type": "WMS", "title": "farbig", "attribution": "BKG", "url": "https://sgx.geodatenzentrum.de/wms_basemapde?", "name": "de_basemapde_web_raster_farbe", "active": false },
|
||||
{ "folder": 14, "type": "WMS", "title": "grau", "attribution": "BKG", "url": "https://sgx.geodatenzentrum.de/wms_basemapde?", "name": "de_basemapde_web_raster_grau", "active": false },
|
||||
{ "folder": 13, "type": "WMS", "title": "farbig", "attribution": "LVermGeo", "url": "https://geo4.service24.rlp.de/wms/dtk5_rp.fcgi?", "name": "rp_dtk5", "active": false },
|
||||
{ "folder": 13, "type": "WMS", "title": "grau", "attribution": "LVermGeo", "url": "https://geo4.service24.rlp.de/wms/dtk5_rp.fcgi?", "name": "rp_dtk5_grau", "active": false }
|
||||
],
|
||||
"folders":
|
||||
[
|
||||
{ "title": "Hintergrund", "parent": -1 },
|
||||
{ "title": "ALKIS Liegenschaften", "parent": -1 },
|
||||
{ "title": "Verwaltungsgrenzen", "parent": -1 },
|
||||
{ "title": "Geofachdaten", "parent": -1 },
|
||||
{ "title": "Kompensationsverzeichnis", "parent": 3 },
|
||||
{ "title": "Kompensationen", "parent": 4 },
|
||||
{ "title": "Eingriffe", "parent": 4 },
|
||||
{ "title": "Ökokonten", "parent": 4 },
|
||||
{ "title": "EMA", "parent": 4 },
|
||||
{ "title": "MAE", "parent": 4 },
|
||||
{ "title": "Schutzgebiete", "parent": 3 },
|
||||
{ "title": "Nationalparke", "parent": 10 },
|
||||
{ "title": "Naturräume", "parent": 10 },
|
||||
{ "title": "Topographisch (DTK5)", "parent": 0 },
|
||||
{ "title": "BaseMap", "parent": 0 },
|
||||
{ "title": "Webatlas", "parent": 0 }
|
||||
],
|
||||
{ "id": "searchplace", "title": "<i class='fas fa-search'></i><span>Suche</span>" },
|
||||
{ "id": "searchparcel", "title": "<i class='fas fa-vector-square'></i><span>Flurstücke</span>" },
|
||||
{ "id": "toolbox", "title": "<i class='fas fa-tools'></i><span>Werkzeuge</span>" },
|
||||
{ "id": "layertree", "title": "<i class='fas fa-layer-group'></i><span>Inhalte</span>" }
|
||||
]
|
||||
},
|
||||
"projections":
|
||||
[
|
||||
[ "EPSG:25832", "+proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs" ]
|
||||
],
|
||||
|
||||
"map":
|
||||
{
|
||||
"projection": "EPSG:25832",
|
||||
"center": [ 385000, 5543000 ],
|
||||
"minZoom": 5,
|
||||
"maxZoom": 22,
|
||||
"center_lonlat": [ 7.0, 50.0 ],
|
||||
"zoom": 9,
|
||||
"attribution": "LANIS RLP",
|
||||
"scalebar": true
|
||||
"min_zoom": 5,
|
||||
"max_zoom": 24,
|
||||
"scalebar": true,
|
||||
"move_tolerance": 5
|
||||
},
|
||||
"folders":
|
||||
[
|
||||
{ "id": "bg", "title": "Hintergrund", "parent": null , "radio": true},
|
||||
{ "id": "alkis", "parent": null, "title": "ALKIS Liegenschaften" },
|
||||
{ "id": "verwaltung", "parent": null, "title": "Verwaltungsgrenzen" },
|
||||
{ "id": "fachdaten", "parent": null, "title": "Geofachdaten" },
|
||||
{ "id": "ksp", "parent": "fachdaten", "title": "Kompensationsverzeichnis"},
|
||||
{ "id": "schutzgebiet", "parent": "fachdaten", "title": "Schutzgebiete"},
|
||||
{ "id": "nationalpark", "parent": "schutzgebiet", "title": "Nationalparke"},
|
||||
{ "id": "naturraum", "parent": "schutzgebiet", "title": "Naturräume" },
|
||||
{ "id": "kom", "parent": "ksp", "title": "Kompensationen" },
|
||||
{ "id": "eiv", "parent": "ksp", "title": "Eingriffe" },
|
||||
{ "id": "oek", "parent": "ksp", "title": "Ökokonten" },
|
||||
{ "id": "ema", "parent": "ksp", "title": "EMA" },
|
||||
{ "id": "mae", "parent": "ksp", "title": "MAE" }
|
||||
],
|
||||
"layers":
|
||||
[
|
||||
{ "id": "webatlas_farbe", "folder": "bg", "type": "WMS", "order": -1, "title": "WebatlasRP farbig", "attribution": "LVermGeo", "url": "https://maps.service24.rlp.de/gisserver/services/RP/RP_WebAtlasRP/MapServer/WmsServer?", "name": "RP_WebAtlasRP", "active": true},
|
||||
{ "id": "webatlas_grau", "folder": "bg", "type": "WMS", "order": -1, "title": "WebatlasRP grau", "attribution": "LVermGeo", "url": "https://maps.service24.rlp.de/gisserver/services/RP/RP_ETRS_Gt/MapServer/WmsServer?", "name": "0", "active": false },
|
||||
{ "id": "luftbilder", "folder": "bg", "type": "WMS", "order": -1, "title": "Luftbilder", "attribution": "LVermGeo", "url": "https://geo4.service24.rlp.de/wms/rp_dop20.fcgi?", "name": "rp_dop20", "active": false },
|
||||
{ "id": "basemap_farbe", "folder": "bg", "type": "WMS", "order": -1, "title": "BasemapDE farbig", "attribution": "BKG", "url": "https://sgx.geodatenzentrum.de/wms_basemapde?", "name": "de_basemapde_web_raster_farbe", "active": false },
|
||||
{ "id": "basemap_grau", "folder": "bg", "type": "WMS", "order": -1, "title": "BasemapDE grau", "attribution": "BKG", "url": "https://sgx.geodatenzentrum.de/wms_basemapde?", "name": "de_basemapde_web_raster_grau", "active": false },
|
||||
{ "id": "dtk_farbe", "folder": "bg", "type": "WMS", "order": -1, "title": "DTK5 farbig", "attribution": "LVermGeo", "url": "https://geo4.service24.rlp.de/wms/dtk5_rp.fcgi?", "name": "rp_dtk5", "active": false },
|
||||
{ "id": "dtk_grau", "folder": "bg", "type": "WMS", "order": -1, "title": "DTK5 grau", "attribution": "LVermGeo", "url": "https://geo4.service24.rlp.de/wms/dtk5_rp.fcgi?", "name": "rp_dtk5_grau", "active": false },
|
||||
|
||||
"output":
|
||||
{ "id": "kom", "folder": "kom", "type": "WMS", "title": "KOM", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=kom_recorded&", "name": "kom_recorded" },
|
||||
{ "id": "kom_rec", "folder": "kom", "type": "WMS", "title": "KOM - In Bearbeitung", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=kom_unrecorded&", "name": "kom_unrecorded" },
|
||||
{ "id": "kom_rec_unfinished", "folder": "kom", "type": "WMS", "title": "KOM - Unvollständige Altfälle", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=kom_unrecorded_old_entries&", "name": "kom_unrecorded_old_entries" },
|
||||
|
||||
{ "id": "eiv", "folder": "eiv", "type": "WMS", "title": "EIV", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=eiv_recorded&", "name": "eiv_recorded" },
|
||||
{ "id": "eiv_rec", "folder": "eiv", "type": "WMS", "title": "EIV - In Bearbeitung", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=eiv_unrecorded&", "name": "eiv_unrecorded" },
|
||||
{ "id": "eiv_rec_unfinished", "folder": "eiv", "type": "WMS", "title": "EIV - Unvollständige Altfälle", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=eiv_unrecorded_old_entries&", "name": "eiv_unrecorded_old_entries" },
|
||||
|
||||
{ "id": "oek", "folder": "oek", "type": "WMS", "title": "OEK", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=oek_recorded&", "name": "oek_recorded" },
|
||||
{ "id": "oek_rec", "folder": "oek", "type": "WMS", "title": "OEK - In Bearbeitung", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=oek_unrecorded&", "name": "oek_unrecorded" },
|
||||
|
||||
{ "id": "ema", "folder": "ema", "type": "WMS", "title": "EMA", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=ema_recorded&", "name": "ema_recorded" },
|
||||
{ "id": "ema_rec", "folder": "ema", "type": "WMS", "title": "EMA - In Bearbeitung", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=ema_unrecorded&", "name": "ema_unrecorded" },
|
||||
|
||||
{ "id": "mae", "folder": "mae", "type": "WMS", "title": "MAE", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=mae&", "name": "mae" },
|
||||
|
||||
{ "id": "nsg", "folder": "schutzgebiet", "type": "WMS", "title": "Naturschutzgebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=naturschutzgebiet&", "name": "naturschutzgebiet" },
|
||||
{ "id": "npz", "folder": "schutzgebiet", "type": "WMS", "title": "Naturparkzonen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=naturparkzonen&", "name": "naturparkzonen" },
|
||||
{ "id": "lsg", "folder": "schutzgebiet", "type": "WMS", "title": "Landschaftsschutzgebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=landschaftsschutzgebiet&", "name": "landschaftsschutzgebiet" },
|
||||
{ "id": "vsg", "folder": "schutzgebiet", "type": "WMS", "title": "Vogelschutzgebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=vogelschutzgebiet&", "name": "vogelschutzgebiet" },
|
||||
{ "id": "ffh", "folder": "schutzgebiet", "type": "WMS", "title": "FFH Gebiete", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=ffh&", "name": "ffh" },
|
||||
|
||||
{"id": "ntpz", "folder": "nationalpark", "type": "WMS", "title": "Nationalpark Zonen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=nationalpark_zonen&", "name": "nationalpark_zonen" },
|
||||
{"id": "ntpg", "folder": "nationalpark", "type": "WMS", "title": "Nationalpark Grenzen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=nationalpark_grenze&", "name": "nationalpark_grenze" },
|
||||
|
||||
{ "id": "natraum_g", "folder": "naturraum", "type": "WMS", "title": "Naturräume Grenzen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=natraum_lkompvo_grenzen&", "name": "natraum_lkompvo_grenzen" },
|
||||
{ "id": "natraum_f", "folder": "naturraum", "type": "WMS", "title": "Naturräume Flächen", "url": "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_ogc/wms_getmap.php?mapfile=natraum_lkompvo&", "name": "natraum_lkompvo" },
|
||||
|
||||
{ "id": "lagebezeichnung", "folder": "alkis", "type": "WMS", "title": "Lagebezeichnungen", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "Lagebezeichnungen" },
|
||||
{ "id": "flurstueck_wms", "folder": "alkis", "type": "WMS", "title": "Flurstücke (WMS)", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "Flurstueck", "active": true},
|
||||
{ "id": "flurstueck_wfs", "folder": "alkis", "type": "WFS", "title": "Flurstücke (WFS; ab hoher Zoomstufe)", "url": "/client/proxy/wfs?", "name": "ave:Flurstueck", "minZoom": 17},
|
||||
{ "id": "gebaeude", "folder": "alkis", "type": "WMS", "title": "Gebäude / Bauwerke", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "GebaeudeBauwerke" },
|
||||
{ "id": "nutzung", "folder": "alkis", "type": "WMS", "title": "Nutzung", "url": "https://geo5.service24.rlp.de/wms/liegenschaften_rp.fcgi?", "name": "Nutzung" },
|
||||
|
||||
{ "id": "lk", "folder": "verwaltung", "type": "WMS", "title": "Landkreise", "url": "https://geo5.service24.rlp.de/wms/verwaltungsgrenzen_rp.fcgi?", "name": "Landkreise" },
|
||||
{ "id": "vg", "folder": "verwaltung", "type": "WMS", "title": "Verbandsgemeinden", "url": "https://geo5.service24.rlp.de/wms/verwaltungsgrenzen_rp.fcgi?", "name": "Verbandsgemeinden" },
|
||||
{ "id": "gmd", "folder": "verwaltung", "type": "WMS", "title": "Gemeinden", "url": "https://geo5.service24.rlp.de/wms/verwaltungsgrenzen_rp.fcgi?", "name": "Gemeinden" }
|
||||
],
|
||||
"layertree":
|
||||
{
|
||||
"id": "netgis-storage"
|
||||
"open": false,
|
||||
"title": "Inhalte",
|
||||
"buttons":
|
||||
[
|
||||
{ "id": "import_layer", "title": "<i class='netgis-icon fas fa-plus' style='font-size: 1em;'></i><span>Hinzufügen...</span>" }
|
||||
]
|
||||
},
|
||||
|
||||
"search":
|
||||
"controls":
|
||||
{
|
||||
"url": "/client/proxy?https://www.geoportal.rlp.de/mapbender/geoportal/gaz_geom_mobile.php?outputFormat=json&resultTarget=web&searchEPSG={epsg}&maxResults=5&maxRows=5&featureClass=P&style=full&searchText={q}&name_startsWith={q}"
|
||||
"buttons":
|
||||
[
|
||||
{ "id": "zoom_in", "icon": "<i class='fas fa-plus'></i>", "title": "Zoom +" },
|
||||
{ "id": "zoom_out", "icon": "<i class='fas fa-minus'></i>", "title": "Zoom -" },
|
||||
{ "id": "zoom_home", "icon": "<i class='fas fa-home'></i>", "title": "Anfangsausdehung" }
|
||||
]
|
||||
},
|
||||
|
||||
"searchParcel":
|
||||
"searchplace":
|
||||
{
|
||||
"nameURL": "/client/proxy?https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_alkis/gem_search.php?placename={q}",
|
||||
"parcelURL": "/client/proxy?https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_alkis/flur_search.php?gmk_gmn={district}&fln={field}&fsn_zae={parcelA}&fsn_nen={parcelB}&export=json",
|
||||
"title": "Adresse...",
|
||||
"url": "/client/proxy?https://www.geoportal.rlp.de/mapbender/geoportal/gaz_geom_mobile.php?outputFormat=json&resultTarget=web&searchEPSG={epsg}&maxResults=5&maxRows=5&featureClass=P&style=full&searchText={query}&name_startsWith={query}",
|
||||
"zoom": 17,
|
||||
"marker_color": "darkgray",
|
||||
"marker_title": "Such-Ergebnis"
|
||||
},
|
||||
"searchparcel":
|
||||
{
|
||||
"open": false,
|
||||
"name_url": "/client/proxy?https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_alkis/gem_search.php?placename={q}",
|
||||
"parcel_url": "/client/proxy?https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/mod_alkis/flur_search.php?gmk_gmn={district}&fln={field}&fsn_zae={parcelA}&fsn_nen={parcelB}&export=json",
|
||||
"districts_service":
|
||||
{
|
||||
"type": "WFS",
|
||||
"url": "http://geo5.service24.rlp.de/wfs/verwaltungsgrenzen_rp.fcgi?",
|
||||
"url": "https://geo5.service24.rlp.de/wfs/verwaltungsgrenzen_rp.fcgi?",
|
||||
"name": "vermkv:gemarkungen_rlp",
|
||||
"order": 10,
|
||||
"minZoom": 11,
|
||||
"maxZoom": 17
|
||||
"format": "application/json; subtype=geojson",
|
||||
"min_zoom": 12
|
||||
},
|
||||
"fields_service":
|
||||
{
|
||||
"url": "http://geo5.service24.rlp.de/wfs/verwaltungsgrenzen_rp.fcgi?",
|
||||
"url": "https://geo5.service24.rlp.de/wfs/verwaltungsgrenzen_rp.fcgi?",
|
||||
"name": "vermkv:fluren_rlp",
|
||||
"filter_property": "gmkgnr"
|
||||
}
|
||||
},
|
||||
"toolbox":
|
||||
{
|
||||
"open": false,
|
||||
"items":
|
||||
[
|
||||
{ "id": "view", "title": "<i class='netgis-icon netgis-text-a fas fa-hand-paper'></i><span>Betrachten</span>" },
|
||||
{ "id": "zoom_box", "title": "<i class='netgis-icon netgis-text-a fas fa-expand'></i><span>Zoom-Rechteck</span>" },
|
||||
{ "id": "view_prev", "title": "<i class='netgis-icon netgis-text-a fas fa-step-backward'></i><span>Vorherige Ansicht</span>" },
|
||||
{ "id": "view_next", "title": "<i class='netgis-icon netgis-text-a fas fa-step-forward'></i><span>Nächste Ansicht</span>" },
|
||||
{ "id": "measure_line", "title": "<i class='netgis-icon netgis-text-a fas fa-ruler'></i><span>Strecke messen</span>" },
|
||||
{ "id": "measure_area", "title": "<i class='netgis-icon netgis-text-a fas fa-ruler-combined'></i><span>Fläche messen</span>" },
|
||||
{ "id": "measure_clear", "title": "<i class='netgis-icon netgis-text-a fas fa-trash-alt'></i><span>Messung löschen</span>" },
|
||||
{ "id": "draw_points", "title": "<i class='netgis-icon netgis-text-a fas fa-map-marker-alt'></i><span>Punkte zeichnen</span>" },
|
||||
{ "id": "draw_lines", "title": "<i class='netgis-icon netgis-text-a fas fa-minus'></i><span>Linien zeichnen</span>" },
|
||||
{ "id": "draw_polygons", "title": "<i class='netgis-icon netgis-text-a fas fa-vector-square'></i><span>Polygone zeichnen</span>" },
|
||||
{ "id": "modify_features", "title": "<i class='netgis-icon netgis-text-a fas fa-arrows-alt'></i><span>Verschieben</span>" },
|
||||
{ "id": "delete_features", "title": "<i class='netgis-icon netgis-text-a fas fa-eraser'></i><span>Löschen</span>" },
|
||||
{ "id": "buffer_features", "title": "<i class='netgis-icon netgis-text-a far fa-dot-circle'></i><span>Puffern</span>" },
|
||||
{ "id": "cut_features", "title": "<i class='netgis-icon netgis-text-a fas fa-cut'></i><span>Ausschneiden</span>" },
|
||||
{ "id": "import_layer", "title": "<i class='netgis-icon netgis-text-a fas fa-upload'></i><span>Importieren</span>" },
|
||||
{ "id": "export", "title": "<i class='netgis-icon netgis-text-a fas fa-save'></i><span>Exportieren</span>" }
|
||||
],
|
||||
"options":
|
||||
{
|
||||
"buffer_features":
|
||||
{
|
||||
"title": "Puffern",
|
||||
"items":
|
||||
[
|
||||
{ "id": "buffer_radius", "type": "integer", "title": "Radius (Meter)" },
|
||||
{ "id": "buffer_segments", "type": "integer", "title": "Segmente" },
|
||||
{ "id": "buffer_submit", "type": "button", "title": "<i class='netgis-icon netgis-text-a fas fa-arrow-circle-right'></i><span>Akzeptieren</span>" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"import":
|
||||
{
|
||||
"geopackageLibURL": "/static/libs/geopackage/4.2.3/"
|
||||
"title": "Ebene hinzufügen",
|
||||
"preview": true,
|
||||
"wms_options": [ "https://sgx.geodatenzentrum.de/wms_topplus_open" ],
|
||||
"wfs_options": [ "http://213.139.159.34:80/geoserver/uesg/wfs" ],
|
||||
"wfs_proxy": "/client/proxy?",
|
||||
"geopackage_lib": "/static/libs/geopackage/4.2.3/"
|
||||
},
|
||||
"export":
|
||||
{
|
||||
"title": "Exportieren",
|
||||
"logo": "/static/assets/logo.png",
|
||||
"gifWebWorker": "/static/libs/gifjs/0.2.0/gif.worker.js",
|
||||
"defaultFilename": "Export",
|
||||
"defaultMargin": 10
|
||||
"gif_worker": "/static/libs/gifjs/0.2.0/gif.worker.js",
|
||||
"default_filename": "Export",
|
||||
"default_margin": 10
|
||||
},
|
||||
"measure":
|
||||
{
|
||||
"line_color": "rgba( 255, 0, 0, 1.0 )",
|
||||
"line_width": 3.0,
|
||||
"line_dash": [ 5, 10 ],
|
||||
"area_fill": "rgba( 255, 0, 0, 0.3 )",
|
||||
"point_radius": 4.0,
|
||||
"point_fill": "rgba( 255, 255, 255, 1.0 )",
|
||||
"point_stroke": "rgba( 0, 0, 0, 1.0 )",
|
||||
"text_color": "#871d33",
|
||||
"text_back": "rgba( 255, 255, 255, 0.7 )"
|
||||
},
|
||||
"tools":
|
||||
{
|
||||
"editable": true,
|
||||
"interactive_render": true,
|
||||
"buffer":
|
||||
{
|
||||
"defaultRadius": 5,
|
||||
"defaultSegments": 2
|
||||
}
|
||||
"default_radius": 5,
|
||||
"default_segments": 3
|
||||
},
|
||||
"snapping":
|
||||
{
|
||||
"show": true,
|
||||
"active": true,
|
||||
"tolerance": 35
|
||||
},
|
||||
"bounds_message": "Ausserhalb des erlaubten Bereichs!",
|
||||
"show_bounds": true
|
||||
},
|
||||
"output":
|
||||
{
|
||||
"id": "netgis-storage"
|
||||
},
|
||||
"attribution":
|
||||
{
|
||||
"prefix": "LANIS"
|
||||
},
|
||||
"styles":
|
||||
{
|
||||
"editLayer":
|
||||
"draw":
|
||||
{
|
||||
"fill": "rgba( 255, 0, 0, 0.2 )",
|
||||
"stroke": "#ff0000",
|
||||
"strokeWidth": 3,
|
||||
"pointRadius": 6
|
||||
"fill": "rgba( 135, 29, 51, 0.5 )",
|
||||
"stroke": "#871d33",
|
||||
"width": 3,
|
||||
"radius": 6,
|
||||
"viewport_labels": true
|
||||
},
|
||||
"non_edit":
|
||||
{
|
||||
"fill": "rgba( 135, 29, 51, 0.5 )",
|
||||
"stroke": "#871d33",
|
||||
"width": 3,
|
||||
"radius": 6,
|
||||
"viewport_labels": true
|
||||
},
|
||||
"select":
|
||||
{
|
||||
"fill": "rgba( 0, 127, 255, 0.5 )",
|
||||
"stroke": "#007fff",
|
||||
"strokeWidth": 3,
|
||||
"pointRadius": 6
|
||||
"width": 3,
|
||||
"radius": 6
|
||||
},
|
||||
"sketch":
|
||||
{
|
||||
"fill": "rgba( 0, 127, 255, 0.2 )",
|
||||
"stroke": "#0080ff",
|
||||
"strokeWidth": 3,
|
||||
"pointRadius": 6
|
||||
"fill": "rgba( 29, 135, 113, 0.5 )",
|
||||
"stroke": "#1D8771",
|
||||
"width": 3,
|
||||
"radius": 6
|
||||
},
|
||||
"error":
|
||||
{
|
||||
"fill": "rgba( 255, 0, 0, 0.5 )",
|
||||
"stroke": "#ff0000",
|
||||
"width": 3,
|
||||
"radius": 6
|
||||
},
|
||||
"bounds":
|
||||
{
|
||||
"fill": "rgba( 0, 0, 0, 0.0 )",
|
||||
"stroke": "#000000",
|
||||
"width": 3,
|
||||
"radius": 6
|
||||
},
|
||||
"modify":
|
||||
{
|
||||
"fill": "rgba( 0, 127, 255, 0.5 )",
|
||||
"stroke": "#0080ff",
|
||||
"strokeWidth": 3,
|
||||
"pointRadius": 6
|
||||
"fill": "rgba( 29, 135, 113, 0.5 )",
|
||||
"stroke": "#1D8771",
|
||||
"width": 3,
|
||||
"radius": 6
|
||||
},
|
||||
"parcel":
|
||||
{
|
||||
"fill": "rgba( 127, 255, 255, 0.5 )",
|
||||
"stroke": "#7fffff",
|
||||
"strokeWidth": 3
|
||||
"fill": "rgba( 127, 0, 0, 0.2 )",
|
||||
"stroke": "rgba( 127, 0, 0, 1.0 )",
|
||||
"width": 2.5
|
||||
},
|
||||
|
||||
"import":
|
||||
{
|
||||
"fill": "rgba( 0, 127, 255, 0.2 )",
|
||||
|
||||
1
templates/map/client/dist/netgis.min.css
vendored
Normal file
1
templates/map/client/dist/netgis.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
8227
templates/map/client/dist/netgis.min.js
vendored
Normal file
8227
templates/map/client/dist/netgis.min.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,13 @@
|
||||
{% load static %}
|
||||
|
||||
<!-- Library Styles -->
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'libs/fontawesome/5.12.0/css/all.min.css' %}" />
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'libs/openlayers/7.2.2/ol.css' %}" />
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'libs/openlayers/10.0.0/ol.css' %}" />
|
||||
|
||||
<!-- Client Styles -->
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'netgis.min.css' %}" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'dist/netgis.min.css' %}" />
|
||||
|
||||
<!-- Library Scripts-->
|
||||
<script type="text/javascript" src="{% static 'libs/openlayers/7.2.2/ol.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'libs/openlayers/10.0.0/ol.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'libs/proj4js/2.6.0/proj4.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'libs/jsts/1.6.1/jsts.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'libs/shapefilejs/4.0.2/shp.js' %}"></script>
|
||||
@@ -19,13 +17,14 @@
|
||||
<script type="text/javascript" src="{% static 'libs/geopackage/4.2.3/geopackage.min.js' %}"></script>
|
||||
|
||||
<!-- Client Scripts -->
|
||||
<script type="text/javascript" src="{% static 'netgis.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'dist/netgis.min.js' %}"></script>
|
||||
|
||||
|
||||
<main id="container" {% if geom_form.read_only %}data-editable="false"{% else %}data-editable="true"{% endif %} style="position: relative; width: 100%; height: 100%;">
|
||||
<main id="container"
|
||||
{% if geom_form.read_only %}data-editable="false"{% else %}data-editable="true"{% endif %}
|
||||
style="position: relative; width: 100%; height: 100%;">
|
||||
</main>
|
||||
|
||||
<input type="hidden" id="netgis-storage" name="geom" value="{{geom_form.fields.geom.initial}}"/>
|
||||
<input type="hidden" id="netgis-storage" name="output" value="{{geom_form.fields.output.initial}}"/>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
|
||||
@@ -109,6 +109,11 @@
|
||||
|
||||
.ol-viewport canvas {
|
||||
all: unset;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ol-viewport {
|
||||
touch-action: pan-x pan-y;
|
||||
}
|
||||
|
||||
.ol-selectable {
|
||||
@@ -343,3 +348,7 @@
|
||||
.ol-overviewmap .ol-overviewmap-box:hover {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.ol-overviewmap .ol-viewport:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
1767
templates/map/client/libs/openlayers/10.0.0/ol.d.ts
vendored
Normal file
1767
templates/map/client/libs/openlayers/10.0.0/ol.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
templates/map/client/libs/openlayers/10.0.0/ol.d.ts.map
Normal file
1
templates/map/client/libs/openlayers/10.0.0/ol.d.ts.map
Normal file
File diff suppressed because one or more lines are too long
2
templates/map/client/libs/openlayers/10.0.0/ol.js
Normal file
2
templates/map/client/libs/openlayers/10.0.0/ol.js
Normal file
File diff suppressed because one or more lines are too long
1
templates/map/client/libs/openlayers/10.0.0/ol.js.map
Normal file
1
templates/map/client/libs/openlayers/10.0.0/ol.js.map
Normal file
File diff suppressed because one or more lines are too long
@@ -1,25 +0,0 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright 2005-present, OpenLayers Contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user