From 60e23d15fc48639b9bbe860492f3b76f81aaa922 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Wed, 13 Apr 2022 11:42:04 +0200 Subject: [PATCH 01/15] #146 Admins and update_all_parcels.py * extends admin backend * adds found_in_codelists to KonovaCodeAdmin to see where a KonovaCode can be found in * improves rendering of after_states and before_states for all AbstractCompensationAdmins * adds geometry_id to all major datatype admin backends * adds st_area like calculation to geometry admin backend * update_all_parcels * orders geometries by size (small to big) to process smaller geometries first and bigger later * adds more output to command for a better overview of what is just going on --- codelist/admin.py | 7 ++++++ compensation/admin.py | 22 +++++++++++++++---- intervention/admin.py | 2 ++ konova/admin.py | 16 ++++++++++++++ .../management/commands/update_all_parcels.py | 13 +++++++++++ konova/models/geometry.py | 3 +++ 6 files changed, 59 insertions(+), 4 deletions(-) diff --git a/codelist/admin.py b/codelist/admin.py index 55ce827d..ccdcb057 100644 --- a/codelist/admin.py +++ b/codelist/admin.py @@ -33,6 +33,7 @@ class KonovaCodeAdmin(admin.ModelAdmin): "is_selectable", "is_leaf", "parent", + "found_in_codelists", ] search_fields = [ @@ -42,6 +43,12 @@ class KonovaCodeAdmin(admin.ModelAdmin): "short_name", ] + def found_in_codelists(self, obj): + codelists = KonovaCodeList.objects.filter( + codes__in=[obj] + ).values_list("id", flat=True) + codelists = "\n".join(str(x) for x in codelists) + return codelists #admin.site.register(KonovaCodeList, KonovaCodeListAdmin) admin.site.register(KonovaCode, KonovaCodeAdmin) diff --git a/compensation/admin.py b/compensation/admin.py index 5f792f76..a5cd1a88 100644 --- a/compensation/admin.py +++ b/compensation/admin.py @@ -21,16 +21,30 @@ class AbstractCompensationAdmin(BaseObjectAdmin): "identifier", "title", "comment", - "after_states", - "before_states", + "list_after_states", + "list_before_states", + "geometry", ] def get_readonly_fields(self, request, obj=None): return super().get_readonly_fields(request, obj) + [ - "after_states", - "before_states", + "list_after_states", + "list_before_states", + "geometry", ] + def list_after_states(self, obj): + states = obj.after_states.all() + states = [str(state) for state in states] + states = "\n".join(states) + return states + + def list_before_states(self, obj): + states = obj.before_states.all() + states = [str(state) for state in states] + states = "\n".join(states) + return states + class CompensationAdmin(AbstractCompensationAdmin): autocomplete_fields = [ diff --git a/intervention/admin.py b/intervention/admin.py index 3d874df6..932ddb93 100644 --- a/intervention/admin.py +++ b/intervention/admin.py @@ -25,12 +25,14 @@ class InterventionAdmin(BaseObjectAdmin): "checked", "recorded", "users", + "geometry", ] def get_readonly_fields(self, request, obj=None): return super().get_readonly_fields(request, obj) + [ "checked", "recorded", + "geometry", ] diff --git a/konova/admin.py b/konova/admin.py index 07be7213..213120ea 100644 --- a/konova/admin.py +++ b/konova/admin.py @@ -8,6 +8,7 @@ Created on: 22.07.21 from django.contrib import admin from konova.models import Geometry, Deadline, GeometryConflict, Parcel, District, Municipal, ParcelGroup +from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP from konova.utils.message_templates import COMPENSATION_REMOVED_TEMPLATE from user.models import UserAction @@ -16,7 +17,22 @@ class GeometryAdmin(admin.ModelAdmin): list_display = [ "id", "created", + "st_area", ] + readonly_fields = [ + "st_area", + "created", + "modified", + ] + + def st_area(self, obj): + val = None + geom = obj.geom + if geom is not None: + geom.transform(ct=DEFAULT_SRID_RLP) + val = geom.area + return val + st_area.short_description = f"Area (srid={DEFAULT_SRID_RLP})" class ParcelAdmin(admin.ModelAdmin): diff --git a/konova/management/commands/update_all_parcels.py b/konova/management/commands/update_all_parcels.py index 9d96ebae..c9dd5158 100644 --- a/konova/management/commands/update_all_parcels.py +++ b/konova/management/commands/update_all_parcels.py @@ -5,6 +5,10 @@ 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 @@ -23,12 +27,21 @@ class Command(BaseKonovaCommand): 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() diff --git a/konova/models/geometry.py b/konova/models/geometry.py index fc484a79..a71a2afa 100644 --- a/konova/models/geometry.py +++ b/konova/models/geometry.py @@ -20,6 +20,9 @@ class Geometry(BaseResource): from konova.settings import DEFAULT_SRID geom = MultiPolygonField(null=True, blank=True, srid=DEFAULT_SRID) + def __str__(self): + return str(self.id) + def save(self, *args, **kwargs): super().save(*args, **kwargs) self.check_for_conflicts() From 83d70b6d59d3325190fea71615ce8b554c368767 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Wed, 13 Apr 2022 14:07:01 +0200 Subject: [PATCH 02/15] #146 (Parcel) table * set default rpp for overview tables from 5 to 10 * improves loading speed of parcel table --- konova/sub_settings/table_settings.py | 2 +- konova/templates/konova/includes/parcels.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/konova/sub_settings/table_settings.py b/konova/sub_settings/table_settings.py index f32a0835..1699ad1b 100644 --- a/konova/sub_settings/table_settings.py +++ b/konova/sub_settings/table_settings.py @@ -19,6 +19,6 @@ PAGE_SIZE_OPTIONS_TUPLES = [ (50, 50), (100, 100), ] -PAGE_SIZE_DEFAULT = 5 +PAGE_SIZE_DEFAULT = 10 PAGE_SIZE_MAX = 100 PAGE_DEFAULT = 1 diff --git a/konova/templates/konova/includes/parcels.html b/konova/templates/konova/includes/parcels.html index 30feda43..a8a882ed 100644 --- a/konova/templates/konova/includes/parcels.html +++ b/konova/templates/konova/includes/parcels.html @@ -8,7 +8,7 @@
-
+
From b85e33dc22cc30cdd4211c3a06639b42f15e5ca5 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Wed, 13 Apr 2022 14:18:32 +0200 Subject: [PATCH 03/15] #146 Share with fix * fixes bug where editable icon on overview table would not glow if user has only team based shared access --- compensation/tables.py | 6 ++---- ema/tables.py | 4 +--- intervention/tables.py | 4 +--- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/compensation/tables.py b/compensation/tables.py index ed89b636..401a7416 100644 --- a/compensation/tables.py +++ b/compensation/tables.py @@ -181,9 +181,7 @@ class CompensationTable(BaseTable, TableRenderMixin): """ if value is None: value = User.objects.none() - has_access = value.filter( - id=self.user.id - ).exists() + has_access = record.is_shared_with(self.user) html = self.render_icn( tooltip=_("Full access granted") if has_access else _("Access not granted"), @@ -343,7 +341,7 @@ class EcoAccountTable(BaseTable, TableRenderMixin): html = "" # Do not use value in here, since value does use unprefetched 'users' manager, where record has already # prefetched users data - has_access = self.user in record.users.all() + has_access = 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", diff --git a/ema/tables.py b/ema/tables.py index 30968f96..38d8a8c0 100644 --- a/ema/tables.py +++ b/ema/tables.py @@ -151,9 +151,7 @@ class EmaTable(BaseTable, TableRenderMixin): """ html = "" - has_access = value.filter( - id=self.user.id - ).exists() + has_access = record.is_shared_with(self.user) html += self.render_icn( tooltip=_("Full access granted") if has_access else _("Access not granted"), diff --git a/intervention/tables.py b/intervention/tables.py index c8ee504e..8f312099 100644 --- a/intervention/tables.py +++ b/intervention/tables.py @@ -177,9 +177,7 @@ class InterventionTable(BaseTable, TableRenderMixin): """ html = "" - has_access = value.filter( - id=self.user.id - ).exists() + has_access = record.is_shared_with(self.user) html += self.render_icn( tooltip=_("Full access granted") if has_access else _("Access not granted"), From bf1c0e207886e3b7aff25947f0c040a92c53dae1 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Wed, 13 Apr 2022 14:57:05 +0200 Subject: [PATCH 04/15] #146 Clickable QR codes * refactors QR codes on report views to be clickable as well (even supported through saved pdf) --- .../report/compensation/report.html | 9 +------ .../report/eco_account/report.html | 9 +------ compensation/views/compensation.py | 24 ++++++++++------- compensation/views/eco_account.py | 26 +++++++++++-------- ema/templates/ema/report/report.html | 9 +------ ema/views.py | 24 ++++++++++------- .../templates/intervention/report/report.html | 9 +------ intervention/views.py | 23 +++++++++------- .../konova/includes/report/qrcodes.html | 19 ++++++++++++++ 9 files changed, 79 insertions(+), 73 deletions(-) create mode 100644 konova/templates/konova/includes/report/qrcodes.html diff --git a/compensation/templates/compensation/report/compensation/report.html b/compensation/templates/compensation/report/compensation/report.html index 25130f72..66205739 100644 --- a/compensation/templates/compensation/report/compensation/report.html +++ b/compensation/templates/compensation/report/compensation/report.html @@ -41,14 +41,7 @@ {% include 'konova/includes/parcels.html' %}
-
-

{% trans 'Open in browser' %}

- {{ qrcode|safe }} -
-
-

{% trans 'View in LANIS' %}

- {{ qrcode_lanis|safe }} -
+ {% include 'konova/includes/report/qrcodes.html' %}
diff --git a/compensation/templates/compensation/report/eco_account/report.html b/compensation/templates/compensation/report/eco_account/report.html index 44496ea8..823a30fb 100644 --- a/compensation/templates/compensation/report/eco_account/report.html +++ b/compensation/templates/compensation/report/eco_account/report.html @@ -54,14 +54,7 @@ {% include 'konova/includes/parcels.html' %}
-
-

{% trans 'Open in browser' %}

- {{ qrcode|safe }} -
-
-

{% trans 'View in LANIS' %}

- {{ qrcode_lanis|safe }} -
+ {% include 'konova/includes/report/qrcodes.html' %}
diff --git a/compensation/views/compensation.py b/compensation/views/compensation.py index 6dcf442b..4068e6bb 100644 --- a/compensation/views/compensation.py +++ b/compensation/views/compensation.py @@ -596,14 +596,12 @@ def report_view(request: HttpRequest, id: str): instance=comp ) parcels = comp.get_underlying_parcels() - qrcode_img = generate_qr_code( - request.build_absolute_uri(reverse("compensation:report", args=(id,))), - 10 - ) - qrcode_img_lanis = generate_qr_code( - comp.get_LANIS_link(), - 7 - ) + + qrcode_url = request.build_absolute_uri(reverse("compensation:report", args=(id,))) + qrcode_img = generate_qr_code(qrcode_url, 10) + qrcode_lanis_url = comp.get_LANIS_link() + qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7) + # Order states by surface before_states = comp.before_states.all().order_by("-surface").prefetch_related("biotope_type") after_states = comp.after_states.all().order_by("-surface").prefetch_related("biotope_type") @@ -611,8 +609,14 @@ def report_view(request: HttpRequest, id: str): context = { "obj": comp, - "qrcode": qrcode_img, - "qrcode_lanis": qrcode_img_lanis, + "qrcode": { + "img": qrcode_img, + "url": qrcode_url, + }, + "qrcode_lanis": { + "img": qrcode_img_lanis, + "url": qrcode_lanis_url, + }, "has_access": False, # disables action buttons during rendering "before_states": before_states, "after_states": after_states, diff --git a/compensation/views/eco_account.py b/compensation/views/eco_account.py index 85b13714..68a5536a 100644 --- a/compensation/views/eco_account.py +++ b/compensation/views/eco_account.py @@ -731,18 +731,16 @@ def report_view(request:HttpRequest, id: str): instance=acc ) parcels = acc.get_underlying_parcels() - qrcode_img = generate_qr_code( - request.build_absolute_uri(reverse("ema:report", args=(id,))), - 10 - ) - qrcode_img_lanis = generate_qr_code( - acc.get_LANIS_link(), - 7 - ) + + qrcode_url = request.build_absolute_uri(reverse("ema:report", args=(id,))) + qrcode_img = generate_qr_code(qrcode_url, 10) + qrcode_lanis_url = acc.get_LANIS_link() + qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7) + # Order states by surface before_states = acc.before_states.all().order_by("-surface").select_related("biotope_type__parent") after_states = acc.after_states.all().order_by("-surface").select_related("biotope_type__parent") - actions = acc.actions.all().select_related("action_type__parent") + actions = acc.actions.all().prefetch_related("action_type__parent") # Reduce amount of db fetched data to the bare minimum we need in the template (deduction's intervention id and identifier) deductions = acc.deductions.all()\ @@ -752,8 +750,14 @@ def report_view(request:HttpRequest, id: str): context = { "obj": acc, - "qrcode": qrcode_img, - "qrcode_lanis": qrcode_img_lanis, + "qrcode": { + "img": qrcode_img, + "url": qrcode_url, + }, + "qrcode_lanis": { + "img": qrcode_img_lanis, + "url": qrcode_lanis_url, + }, "has_access": False, # disables action buttons during rendering "before_states": before_states, "after_states": after_states, diff --git a/ema/templates/ema/report/report.html b/ema/templates/ema/report/report.html index 86252c0a..40b11084 100644 --- a/ema/templates/ema/report/report.html +++ b/ema/templates/ema/report/report.html @@ -41,14 +41,7 @@ {% include 'konova/includes/parcels.html' %}
-
-

{% trans 'Open in browser' %}

- {{ qrcode|safe }} -
-
-

{% trans 'View in LANIS' %}

- {{ qrcode_lanis|safe }} -
+ {% include 'konova/includes/report/qrcodes.html' %}
diff --git a/ema/views.py b/ema/views.py index c145511f..debd31da 100644 --- a/ema/views.py +++ b/ema/views.py @@ -563,14 +563,12 @@ def report_view(request:HttpRequest, id: str): instance=ema, ) parcels = ema.get_underlying_parcels() - qrcode_img = generate_qr_code( - request.build_absolute_uri(reverse("ema:report", args=(id,))), - 10 - ) - qrcode_img_lanis = generate_qr_code( - ema.get_LANIS_link(), - 7 - ) + + qrcode_url = request.build_absolute_uri(reverse("ema:report", args=(id,))) + qrcode_img = generate_qr_code(qrcode_url, 10) + qrcode_lanis_url = ema.get_LANIS_link() + qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7) + # Order states by surface before_states = ema.before_states.all().order_by("-surface").prefetch_related("biotope_type") after_states = ema.after_states.all().order_by("-surface").prefetch_related("biotope_type") @@ -578,8 +576,14 @@ def report_view(request:HttpRequest, id: str): context = { "obj": ema, - "qrcode": qrcode_img, - "qrcode_lanis": qrcode_img_lanis, + "qrcode": { + "img": qrcode_img, + "url": qrcode_url + }, + "qrcode_lanis": { + "img": qrcode_img_lanis, + "url": qrcode_lanis_url + }, "has_access": False, # disables action buttons during rendering "before_states": before_states, "after_states": after_states, diff --git a/intervention/templates/intervention/report/report.html b/intervention/templates/intervention/report/report.html index ccc2f226..e6f13c35 100644 --- a/intervention/templates/intervention/report/report.html +++ b/intervention/templates/intervention/report/report.html @@ -100,14 +100,7 @@ {% include 'konova/includes/parcels.html' %}
-
-

{% trans 'Open in browser' %}

- {{ qrcode|safe }} -
-
-

{% trans 'View in LANIS' %}

- {{ qrcode_lanis|safe }} -
+ {% include 'konova/includes/report/qrcodes.html' %}
diff --git a/intervention/views.py b/intervention/views.py index 3004a79f..b2b78eee 100644 --- a/intervention/views.py +++ b/intervention/views.py @@ -693,19 +693,22 @@ def report_view(request:HttpRequest, id: str): distinct_deductions = intervention.deductions.all().distinct( "account" ) - qrcode_img = generate_qr_code( - request.build_absolute_uri(reverse("intervention:report", args=(id,))), - 10 - ) - qrcode_img_lanis = generate_qr_code( - intervention.get_LANIS_link(), - 7 - ) + qrcode_url = request.build_absolute_uri(reverse("intervention:report", args=(id,))) + qrcode_img = generate_qr_code(qrcode_url, 10) + qrcode_lanis_url = intervention.get_LANIS_link() + qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7) + context = { "obj": intervention, "deductions": distinct_deductions, - "qrcode": qrcode_img, - "qrcode_lanis": qrcode_img_lanis, + "qrcode": { + "img": qrcode_img, + "url": qrcode_url, + }, + "qrcode_lanis": { + "img": qrcode_img_lanis, + "url": qrcode_lanis_url, + }, "geom_form": geom_form, "parcels": parcels, TAB_TITLE_IDENTIFIER: tab_title, diff --git a/konova/templates/konova/includes/report/qrcodes.html b/konova/templates/konova/includes/report/qrcodes.html new file mode 100644 index 00000000..5b52d0c1 --- /dev/null +++ b/konova/templates/konova/includes/report/qrcodes.html @@ -0,0 +1,19 @@ +{% load i18n %} + + + + \ No newline at end of file From 87fae51144d9721931aaa205db7ae29a3ae7abbb Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Wed, 13 Apr 2022 15:52:41 +0200 Subject: [PATCH 05/15] #146 Team leave * adds button and functionality for leaving a team * if the admin leaves the team, another user will be chosen as new admin automatically * improves Team (django) admin backend * better control over user adding-removing * only added team members are selectable as admin --- locale/de/LC_MESSAGES/django.mo | Bin 41022 -> 41223 bytes locale/de/LC_MESSAGES/django.po | 88 +++++++++++++++------------- user/admin.py | 9 +++ user/forms.py | 9 +++ user/models/team.py | 14 +++++ user/templates/user/team/index.html | 3 + user/urls.py | 1 + user/views.py | 23 +++++++- 8 files changed, 105 insertions(+), 42 deletions(-) diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index 6459128eea239987fe10a52b6584f1130ae233fc..68305e78437c38918613b70d5d18bddc67804d89 100644 GIT binary patch delta 11818 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 L$i2U;o!9>WbzY8h delta 11600 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 K`|*{@e*XuSPjL(Y diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 1cb4871a..08aed93d 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -26,7 +26,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-04-12 10:28+0200\n" +"POT-Creation-Date: 2022-04-13 15:13+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -154,7 +154,7 @@ msgstr "Geprüft" #: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:9 #: analysis/templates/analysis/reports/includes/intervention/laws.html:20 #: analysis/templates/analysis/reports/includes/old_data/amount.html:18 -#: compensation/tables.py:46 compensation/tables.py:222 +#: compensation/tables.py:46 compensation/tables.py:220 #: compensation/templates/compensation/detail/compensation/view.html:78 #: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31 #: compensation/templates/compensation/detail/eco_account/view.html:45 @@ -294,7 +294,7 @@ msgid "Intervention" msgstr "Eingriff" #: analysis/templates/analysis/reports/includes/old_data/amount.html:34 -#: compensation/tables.py:266 +#: compensation/tables.py:264 #: compensation/templates/compensation/detail/eco_account/view.html:20 #: intervention/forms/modalForms.py:348 intervention/forms/modalForms.py:355 #: konova/templates/konova/includes/quickstart/ecoaccounts.html:4 @@ -315,7 +315,7 @@ msgid "Show only unrecorded" msgstr "Nur unverzeichnete anzeigen" #: compensation/forms/forms.py:32 compensation/tables.py:25 -#: compensation/tables.py:197 ema/tables.py:29 intervention/forms/forms.py:28 +#: compensation/tables.py:195 ema/tables.py:29 intervention/forms/forms.py:28 #: intervention/tables.py:24 #: intervention/templates/intervention/detail/includes/compensations.html:30 msgid "Identifier" @@ -327,7 +327,7 @@ msgid "Generated automatically" msgstr "Automatisch generiert" #: compensation/forms/forms.py:44 compensation/tables.py:30 -#: compensation/tables.py:202 +#: compensation/tables.py:200 #: compensation/templates/compensation/detail/compensation/includes/documents.html:28 #: compensation/templates/compensation/detail/compensation/view.html:32 #: compensation/templates/compensation/detail/eco_account/includes/documents.html:28 @@ -675,22 +675,22 @@ msgstr "" "Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar einstellen " "wollen. Kontaktieren Sie die für die Abbuchungen verantwortlichen Nutzer!" -#: compensation/tables.py:35 compensation/tables.py:207 ema/tables.py:39 +#: compensation/tables.py:35 compensation/tables.py:205 ema/tables.py:39 #: intervention/tables.py:34 konova/filters/mixins.py:98 msgid "Parcel gmrkng" msgstr "Gemarkung" -#: compensation/tables.py:52 compensation/tables.py:228 ema/tables.py:50 +#: compensation/tables.py:52 compensation/tables.py:226 ema/tables.py:50 #: intervention/tables.py:51 msgid "Editable" msgstr "Freigegeben" -#: compensation/tables.py:58 compensation/tables.py:234 ema/tables.py:56 +#: compensation/tables.py:58 compensation/tables.py:232 ema/tables.py:56 #: intervention/tables.py:57 msgid "Last edit" msgstr "Zuletzt bearbeitet" -#: compensation/tables.py:89 compensation/tables.py:266 ema/tables.py:89 +#: compensation/tables.py:89 compensation/tables.py:264 ema/tables.py:89 #: intervention/tables.py:88 msgid "Open {}" msgstr "Öffne {}" @@ -713,32 +713,32 @@ msgstr "Am {} von {} geprüft worden" msgid "Not recorded yet" msgstr "Noch nicht verzeichnet" -#: compensation/tables.py:165 compensation/tables.py:326 ema/tables.py:136 +#: compensation/tables.py:165 compensation/tables.py:324 ema/tables.py:136 #: intervention/tables.py:162 msgid "Recorded on {} by {}" msgstr "Am {} von {} verzeichnet worden" -#: compensation/tables.py:189 compensation/tables.py:348 ema/tables.py:159 -#: intervention/tables.py:185 +#: compensation/tables.py:187 compensation/tables.py:346 ema/tables.py:157 +#: intervention/tables.py:183 msgid "Full access granted" msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden" -#: compensation/tables.py:189 compensation/tables.py:348 ema/tables.py:159 -#: intervention/tables.py:185 +#: compensation/tables.py:187 compensation/tables.py:346 ema/tables.py:157 +#: intervention/tables.py:183 msgid "Access not granted" msgstr "Nicht freigegeben - Datensatz nur lesbar" -#: compensation/tables.py:212 +#: compensation/tables.py:210 #: compensation/templates/compensation/detail/eco_account/view.html:36 #: konova/templates/konova/widgets/progressbar.html:3 msgid "Available" msgstr "Verfügbar" -#: compensation/tables.py:243 +#: compensation/tables.py:241 msgid "Eco Accounts" msgstr "Ökokonten" -#: compensation/tables.py:321 +#: compensation/tables.py:319 msgid "Not recorded yet. Can not be used for deductions, yet." msgstr "" "Noch nicht verzeichnet. Kann noch nicht für Abbuchungen genutzt werden." @@ -1112,20 +1112,6 @@ msgstr "Maßnahmenträger" msgid "Report" msgstr "Bericht" -#: compensation/templates/compensation/report/compensation/report.html:45 -#: compensation/templates/compensation/report/eco_account/report.html:58 -#: ema/templates/ema/report/report.html:45 -#: intervention/templates/intervention/report/report.html:104 -msgid "Open in browser" -msgstr "Im Browser öffnen" - -#: compensation/templates/compensation/report/compensation/report.html:49 -#: compensation/templates/compensation/report/eco_account/report.html:62 -#: ema/templates/ema/report/report.html:49 -#: intervention/templates/intervention/report/report.html:108 -msgid "View in LANIS" -msgstr "In LANIS öffnen" - #: compensation/templates/compensation/report/eco_account/report.html:24 msgid "Deductions for" msgstr "Abbuchungen für" @@ -1204,22 +1190,22 @@ msgstr "{} entzeichnet" msgid "{} recorded" msgstr "{} verzeichnet" -#: compensation/views/eco_account.py:792 ema/views.py:617 +#: compensation/views/eco_account.py:796 ema/views.py:621 #: intervention/views.py:428 msgid "{} has already been shared with you" msgstr "{} wurde bereits für Sie freigegeben" -#: compensation/views/eco_account.py:797 ema/views.py:622 +#: compensation/views/eco_account.py:801 ema/views.py:626 #: intervention/views.py:433 msgid "{} has been shared with you" msgstr "{} ist nun für Sie freigegeben" -#: compensation/views/eco_account.py:804 ema/views.py:629 +#: compensation/views/eco_account.py:808 ema/views.py:633 #: intervention/views.py:440 msgid "Share link invalid" msgstr "Freigabelink ungültig" -#: compensation/views/eco_account.py:827 ema/views.py:652 +#: compensation/views/eco_account.py:831 ema/views.py:656 #: intervention/views.py:463 msgid "Share settings updated" msgstr "Freigabe Einstellungen aktualisiert" @@ -1802,6 +1788,14 @@ msgstr "Neu" msgid "Show" msgstr "Anzeigen" +#: konova/templates/konova/includes/report/qrcodes.html:7 +msgid "Open in browser" +msgstr "Im Browser öffnen" + +#: konova/templates/konova/includes/report/qrcodes.html:15 +msgid "View in LANIS" +msgstr "In LANIS öffnen" + #: konova/templates/konova/widgets/checkbox-tree-select.html:4 #: templates/generic_index.html:56 msgid "Search" @@ -2451,9 +2445,9 @@ msgid "" " " msgstr "" "\n" -" Diese Daten sind noch nicht veröffentlicht und/oder haben das Bestandskraftdatum noch nicht erreicht. " -"Sie können daher aktuell nicht eingesehen werden. Schauen Sie zu einem späteren Zeitpunkt " -"wieder vorbei. \n" +" Diese Daten sind noch nicht veröffentlicht und/oder haben das " +"Bestandskraftdatum noch nicht erreicht. Sie können daher aktuell nicht " +"eingesehen werden. Schauen Sie zu einem späteren Zeitpunkt wieder vorbei. \n" " " #: templates/table/gmrkng_col.html:6 @@ -2504,11 +2498,11 @@ msgstr "Neuen Token generieren" msgid "A new token needs to be validated by an administrator!" msgstr "Neue Tokens müssen durch Administratoren freigeschaltet werden!" -#: user/forms.py:168 user/forms.py:172 user/forms.py:323 user/forms.py:328 +#: user/forms.py:168 user/forms.py:172 user/forms.py:332 user/forms.py:337 msgid "Team name" msgstr "Team Name" -#: user/forms.py:179 user/forms.py:336 user/templates/user/team/index.html:30 +#: user/forms.py:179 user/forms.py:345 user/templates/user/team/index.html:30 msgid "Description" msgstr "Beschreibung" @@ -2556,7 +2550,11 @@ msgstr "Gewählter Administrator ({}) muss ein Mitglied des Teams sein." msgid "Edit team" msgstr "Team bearbeiten" -#: user/forms.py:347 +#: user/forms.py:323 user/templates/user/team/index.html:58 +msgid "Leave team" +msgstr "Team verlassen" + +#: user/forms.py:356 msgid "Team" msgstr "Team" @@ -2702,6 +2700,14 @@ msgstr "Team bearbeitet" msgid "Team removed" msgstr "Team gelöscht" +#: user/views.py:218 +msgid "You are not a member of this team" +msgstr "Sie sind kein Mitglied dieses Teams" + +#: user/views.py:225 +msgid "Left Team" +msgstr "Team verlassen" + #: venv/lib/python3.7/site-packages/bootstrap4/components.py:17 #: venv/lib/python3.7/site-packages/bootstrap4/templates/bootstrap4/form_errors.html:3 #: venv/lib/python3.7/site-packages/bootstrap4/templates/bootstrap4/messages.html:4 diff --git a/user/admin.py b/user/admin.py index 1aeacee3..f4ef9fce 100644 --- a/user/admin.py +++ b/user/admin.py @@ -74,6 +74,15 @@ class TeamAdmin(admin.ModelAdmin): "name", "description", ] + filter_horizontal = [ + "users" + ] + + def formfield_for_foreignkey(self, db_field, request, **kwargs): + if db_field.name == "admin": + team_id = request.resolver_match.kwargs.get("object_id", None) + kwargs["queryset"] = User.objects.filter(teams__id__in=[team_id]) + return super().formfield_for_foreignkey(db_field, request, **kwargs) admin.site.register(User, UserAdmin) diff --git a/user/forms.py b/user/forms.py index 34c8fab9..4a657afb 100644 --- a/user/forms.py +++ b/user/forms.py @@ -317,6 +317,15 @@ class RemoveTeamModalForm(RemoveModalForm): pass +class LeaveTeamModalForm(RemoveModalForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.form_title = _("Leave team") + + def save(self): + self.instance.remove_user(self.user) + + class TeamDataForm(BaseModalForm): name = forms.CharField( label_suffix="", diff --git a/user/models/team.py b/user/models/team.py index e36c95b4..f14c7e0f 100644 --- a/user/models/team.py +++ b/user/models/team.py @@ -93,3 +93,17 @@ class Team(UuidModel): """ mailer = Mailer() mailer.send_mail_shared_data_deleted_team(obj_identifier, obj_title, self) + + def remove_user(self, user): + """ Removes a user from the team + + Args: + user (User): The user to be removed + + Returns: + + """ + self.users.remove(user) + if self.admin == user: + self.admin = self.users.first() + self.save() diff --git a/user/templates/user/team/index.html b/user/templates/user/team/index.html index d2040a35..3cd08e74 100644 --- a/user/templates/user/team/index.html +++ b/user/templates/user/team/index.html @@ -46,6 +46,9 @@ {% endfor %} + {% if team.admin == user %} + + +{% endif %} \ No newline at end of file diff --git a/konova/templates/konova/includes/parcel_table.html b/konova/templates/konova/includes/parcels/parcel_table_frame.html similarity index 75% rename from konova/templates/konova/includes/parcel_table.html rename to konova/templates/konova/includes/parcels/parcel_table_frame.html index 76503572..4b4a760d 100644 --- a/konova/templates/konova/includes/parcel_table.html +++ b/konova/templates/konova/includes/parcels/parcel_table_frame.html @@ -36,17 +36,8 @@ {% trans 'Parcel number' %} - - {% for parcel in parcels %} - - {{parcel.parcel_group.name|default_if_none:"-"}} - {{parcel.parcel_group.key|default_if_none:"-"}} - {{parcel.flr|default_if_none:"-"|unlocalize}} - {{parcel.flrstck_zhlr|default_if_none:"-"|unlocalize}} - {{parcel.flrstck_nnr|default_if_none:"-"|unlocalize}} - - {% endfor %} - + + {% include 'konova/includes/parcels/parcel_table_content.html' %} {% endif %} diff --git a/konova/templates/konova/includes/parcels.html b/konova/templates/konova/includes/parcels/parcels.html similarity index 100% rename from konova/templates/konova/includes/parcels.html rename to konova/templates/konova/includes/parcels/parcels.html diff --git a/konova/urls.py b/konova/urls.py index d2458f50..00386a11 100644 --- a/konova/urls.py +++ b/konova/urls.py @@ -24,7 +24,7 @@ from konova.autocompletes import EcoAccountAutocomplete, \ ShareTeamAutocomplete, HandlerCodeAutocomplete from konova.settings import SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY, DEBUG from konova.sso.sso import KonovaSSOClient -from konova.views import logout_view, home_view, get_geom_parcels +from konova.views import logout_view, home_view, get_geom_parcels, get_geom_parcels_content sso_client = KonovaSSOClient(SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY) urlpatterns = [ @@ -40,7 +40,8 @@ urlpatterns = [ path('cl/', include("codelist.urls")), path('analysis/', include("analysis.urls")), path('api/', include("api.urls")), - path('geom//parcels', get_geom_parcels, name="geometry-parcels"), + path('geom//parcels/', get_geom_parcels, name="geometry-parcels"), + path('geom//parcels/', get_geom_parcels_content, name="geometry-parcels-content"), # Autocomplete paths for all apps path("atcmplt/eco-accounts", EcoAccountAutocomplete.as_view(), name="accounts-autocomplete"), diff --git a/konova/views.py b/konova/views.py index 2fd5ff91..db830750 100644 --- a/konova/views.py +++ b/konova/views.py @@ -115,7 +115,7 @@ def get_geom_parcels(request: HttpRequest, id: str): # HTTP code 286 states that the HTMX should stop polling for updates # https://htmx.org/docs/#polling status_code = 286 - template = "konova/includes/parcel_table.html" + template = "konova/includes/parcels/parcel_table_frame.html" geom = get_object_or_404(Geometry, id=id) parcels = geom.get_underlying_parcels() geos_geom = geom.geom @@ -133,9 +133,18 @@ def get_geom_parcels(request: HttpRequest, id: str): parcels = parcels.order_by("-municipal", "flr", "flrstck_zhlr", "flrstck_nnr") municipals = parcels.order_by("municipal").distinct("municipal").values("municipal__id") municipals = Municipal.objects.filter(id__in=municipals) + + rpp = 50 + parcels = parcels[:rpp] + next_page = 1 + if len(parcels) < rpp: + next_page = None + context = { "parcels": parcels, "municipals": municipals, + "geom_id": str(id), + "next_page": next_page, } html = render_to_string(template, context, request) return HttpResponse(html, status=status_code) @@ -143,6 +152,36 @@ def get_geom_parcels(request: HttpRequest, id: str): return HttpResponse(None, status=404) +@login_required +def get_geom_parcels_content(request:HttpRequest, id: str, page: int): + if page < 0: + raise AssertionError("Parcel page can not be negative") + + # HTTP code 286 states that the HTMX should stop polling for updates + # https://htmx.org/docs/#polling + status_code = 286 + template = "konova/includes/parcels/parcel_table_content.html" + geom = get_object_or_404(Geometry, id=id) + parcels = geom.get_underlying_parcels() + + parcels = parcels.order_by("-municipal", "flr", "flrstck_zhlr", "flrstck_nnr") + rpp = 50 + from_p = rpp * (page-1) + to_p = rpp * (page) + next_page = page + 1 + parcels = parcels[from_p:to_p] + if len(parcels) < rpp: + next_page = None + + context = { + "parcels": parcels, + "geom_id": str(id), + "next_page": next_page, + } + html = render_to_string(template, context, request) + return HttpResponse(html, status=status_code) + + def get_404_view(request: HttpRequest, exception=None): """ Returns a 404 handling view diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index 9626e763ea04a135d76675baf28ba22d85ea7eea..4557506492ae0c22aef1fdb700430c20118e8ffa 100644 GIT binary patch delta 11797 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 diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 2a78deb7..35ee2c5c 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -26,7 +26,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-04-19 13:28+0200\n" +"POT-Creation-Date: 2022-04-21 14:16+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1582,7 +1582,7 @@ msgid "Search for file number" msgstr "Nach Aktenzeichen suchen" #: konova/filters/mixins.py:85 -#: konova/templates/konova/includes/parcel_table.html:13 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:13 msgid "District" msgstr "Kreis" @@ -1595,7 +1595,7 @@ msgid "Search for parcel gmrkng" msgstr "Nach Gemarkung suchen" #: konova/filters/mixins.py:111 -#: konova/templates/konova/includes/parcel_table.html:34 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:34 msgid "Parcel" msgstr "Flur" @@ -1604,7 +1604,7 @@ msgid "Search for parcel" msgstr "Nach Flur suchen" #: konova/filters/mixins.py:124 -#: konova/templates/konova/includes/parcel_table.html:35 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:35 msgid "Parcel counter" msgstr "Flurstückzähler" @@ -1613,7 +1613,7 @@ msgid "Search for parcel counter" msgstr "Nach Flurstückzähler suchen" #: konova/filters/mixins.py:138 -#: konova/templates/konova/includes/parcel_table.html:36 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:36 msgid "Parcel number" msgstr "Flurstücknenner" @@ -1748,33 +1748,37 @@ msgstr "" msgid "English" msgstr "" -#: konova/templates/konova/includes/parcel_table.html:5 +#: konova/templates/konova/includes/parcels/parcel_table_content.html:18 +msgid "Show more..." +msgstr "Mehr anzeigen..." + +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:5 msgid "Parcels can not be calculated, since no geometry is given." msgstr "" "Flurstücke können nicht berechnet werden, da keine Geometrie eingegeben " "wurde." -#: konova/templates/konova/includes/parcel_table.html:11 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:11 msgid "Municipal" msgstr "Gemeinde" -#: konova/templates/konova/includes/parcel_table.html:12 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:12 msgid "Municipal key" msgstr "Gemeindeschlüssel" -#: konova/templates/konova/includes/parcel_table.html:14 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:14 msgid "District key" msgstr "Kreisschlüssel" -#: konova/templates/konova/includes/parcel_table.html:32 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:32 msgid "Parcel group" msgstr "Gemarkung" -#: konova/templates/konova/includes/parcel_table.html:33 +#: konova/templates/konova/includes/parcels/parcel_table_frame.html:33 msgid "Parcel group key" msgstr "Gemarkungsschlüssel" -#: konova/templates/konova/includes/parcels.html:7 +#: konova/templates/konova/includes/parcels/parcels.html:7 msgid "Spatial reference" msgstr "Raumreferenz" From 9c2bdcdacfe801952cda8c26eefd85324a29c25a Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Thu, 21 Apr 2022 14:36:55 +0200 Subject: [PATCH 11/15] #151 Parcel table infinite scroll * refactors button for further loading to infinite scroll * adds code documentation --- .../parcels/parcel_table_content.html | 40 +++++++++---------- .../includes/parcels/parcel_table_frame.html | 2 +- konova/views.py | 21 ++++++++-- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/konova/templates/konova/includes/parcels/parcel_table_content.html b/konova/templates/konova/includes/parcels/parcel_table_content.html index 0cb5ce11..549a8092 100644 --- a/konova/templates/konova/includes/parcels/parcel_table_content.html +++ b/konova/templates/konova/includes/parcels/parcel_table_content.html @@ -1,22 +1,22 @@ {% load l10n i18n %} {% for parcel in parcels %} - - {{parcel.parcel_group.name|default_if_none:"-"}} - {{parcel.parcel_group.key|default_if_none:"-"}} - {{parcel.flr|default_if_none:"-"|unlocalize}} - {{parcel.flrstck_zhlr|default_if_none:"-"|unlocalize}} - {{parcel.flrstck_nnr|default_if_none:"-"|unlocalize}} - -{% endfor %} -{% if next_page %} - - - - - -{% endif %} \ No newline at end of file + {% if forloop.last and next_page %} + + {{parcel.parcel_group.name|default_if_none:"-"}} + {{parcel.parcel_group.key|default_if_none:"-"}} + {{parcel.flr|default_if_none:"-"|unlocalize}} + {{parcel.flrstck_zhlr|default_if_none:"-"|unlocalize}} + {{parcel.flrstck_nnr|default_if_none:"-"|unlocalize}} + + {% else %} + + {{parcel.parcel_group.name|default_if_none:"-"}} + {{parcel.parcel_group.key|default_if_none:"-"}} + {{parcel.flr|default_if_none:"-"|unlocalize}} + {{parcel.flrstck_zhlr|default_if_none:"-"|unlocalize}} + {{parcel.flrstck_nnr|default_if_none:"-"|unlocalize}} + + {% endif %} +{% endfor %} \ No newline at end of file diff --git a/konova/templates/konova/includes/parcels/parcel_table_frame.html b/konova/templates/konova/includes/parcels/parcel_table_frame.html index 4b4a760d..e3292004 100644 --- a/konova/templates/konova/includes/parcels/parcel_table_frame.html +++ b/konova/templates/konova/includes/parcels/parcel_table_frame.html @@ -36,7 +36,7 @@ {% trans 'Parcel number' %} - + {% include 'konova/includes/parcels/parcel_table_content.html' %} diff --git a/konova/views.py b/konova/views.py index db830750..97cb7d82 100644 --- a/konova/views.py +++ b/konova/views.py @@ -110,7 +110,7 @@ def get_geom_parcels(request: HttpRequest, id: str): id (str): The geometry's id Returns: - + A rendered piece of HTML """ # HTTP code 286 states that the HTMX should stop polling for updates # https://htmx.org/docs/#polling @@ -134,7 +134,7 @@ def get_geom_parcels(request: HttpRequest, id: str): municipals = parcels.order_by("municipal").distinct("municipal").values("municipal__id") municipals = Municipal.objects.filter(id__in=municipals) - rpp = 50 + rpp = 100 parcels = parcels[:rpp] next_page = 1 if len(parcels) < rpp: @@ -153,7 +153,20 @@ def get_geom_parcels(request: HttpRequest, id: str): @login_required -def get_geom_parcels_content(request:HttpRequest, id: str, page: int): +def get_geom_parcels_content(request: HttpRequest, id: str, page: int): + """ Getter for infinite scroll of HTMX + + Returns parcels of a specific page/slice of the found parcel set. + Implementation of infinite scroll htmx example: https://htmx.org/examples/infinite-scroll/ + + Args: + request (HttpRequest): The incoming request + id (str): The geometry's id + page (int): The requested page number + + Returns: + A rendered piece of HTML + """ if page < 0: raise AssertionError("Parcel page can not be negative") @@ -165,7 +178,7 @@ def get_geom_parcels_content(request:HttpRequest, id: str, page: int): parcels = geom.get_underlying_parcels() parcels = parcels.order_by("-municipal", "flr", "flrstck_zhlr", "flrstck_nnr") - rpp = 50 + rpp = 100 from_p = rpp * (page-1) to_p = rpp * (page) next_page = page + 1 From eb975cd3c5c201a24e8b1551da4c61c04b810741 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Mon, 25 Apr 2022 11:16:51 +0200 Subject: [PATCH 12/15] #149 Send on changes * changes trigger for sending data to EGON: on each new payment, edited payment or deleted payment action, the data will be sent to EGON instead only once on "recording" --- compensation/forms/modalForms.py | 1 + intervention/models/intervention.py | 4 ++- intervention/utils/egon_export.py | 40 ++++++++++++++++++----------- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/compensation/forms/modalForms.py b/compensation/forms/modalForms.py index ebfb1ebd..8404c7ad 100644 --- a/compensation/forms/modalForms.py +++ b/compensation/forms/modalForms.py @@ -128,6 +128,7 @@ class EditPaymentModalForm(NewPaymentForm): payment.comment = self.cleaned_data.get("comment", None) payment.save() self.instance.mark_as_edited(self.user, self.request, edit_comment=PAYMENT_EDITED) + self.instance.send_data_to_egon() return payment diff --git a/intervention/models/intervention.py b/intervention/models/intervention.py index c215a139..dd15beb1 100644 --- a/intervention/models/intervention.py +++ b/intervention/models/intervention.py @@ -145,7 +145,6 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec def set_recorded(self, user: User) -> UserActionLogEntry: log_entry = super().set_recorded(user) self.add_log_entry_to_compensations(log_entry) - self.send_data_to_egon() return log_entry def add_log_entry_to_compensations(self, log_entry: UserActionLogEntry): @@ -183,6 +182,8 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec intervention=self, ) self.mark_as_edited(user, form.request, edit_comment=PAYMENT_ADDED) + + self.send_data_to_egon() return pay def add_revocation(self, form): @@ -347,6 +348,7 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec with transaction.atomic(): payment.delete() self.mark_as_edited(user, request=form.request, edit_comment=PAYMENT_REMOVED) + self.send_data_to_egon() class InterventionDocument(AbstractDocument): diff --git a/intervention/utils/egon_export.py b/intervention/utils/egon_export.py index 1ef9f727..14ea6b61 100644 --- a/intervention/utils/egon_export.py +++ b/intervention/utils/egon_export.py @@ -156,10 +156,20 @@ class EgonGmlBuilder: def build_gml(self): comp_type, comp_type_code = self._gen_kompensationsArt() - payment_date = self.intervention.payments.first().due_on - if payment_date is not None: + payment = self.intervention.payments.first() + payment_date = None + if payment is not None: + payment_date = payment.due_on payment_date = payment_date.strftime(DEFAULT_DATE_FORMAT) + cons_office = self.intervention.responsible.conservation_office + reg_office = self.intervention.responsible.registration_office + law = self.intervention.legal.laws.first() + process_type = self.intervention.legal.process_type + handler = self.intervention.responsible.handler + reg_date = self.intervention.legal.registration_date + bind_date = self.intervention.legal.binding_date + xml_dict = { "wfs:FeatureCollection": { "@xmlns:wfs": "http://www.opengis.net/wfs", @@ -174,12 +184,12 @@ class EgonGmlBuilder: "oneo:azZulassungsstelle": self.intervention.responsible.registration_file_number, "oneo:bemerkungZulassungsstelle": None, "oneo:eintragungsstelle": { - "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/907/{self.intervention.responsible.conservation_office.atom_id}", - "#text": self.intervention.responsible.conservation_office.long_name + "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/907/{cons_office.atom_id if cons_office else None}", + "#text": cons_office.long_name if cons_office else None }, "oneo:zulassungsstelle": { - "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1053/{self.intervention.responsible.registration_office.atom_id}", - "#text": self.intervention.responsible.registration_office.long_name + "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1053/{reg_office.atom_id if reg_office else None}", + "#text": reg_office.long_name if reg_office else None }, "oneo:ersatzzahlung": self._sum_all_payments(), "oneo:kompensationsart": { @@ -187,20 +197,20 @@ class EgonGmlBuilder: "#text": comp_type }, "oneo:verfahrensrecht": { - "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1048/{self.intervention.legal.laws.first().atom_id}", - "#text": self.intervention.legal.laws.first().short_name + "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1048/{law.atom_id if law else None}", + "#text": law.short_name if law else None }, "oneo:verfahrenstyp": { - "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/44382/{self.intervention.legal.process_type.atom_id}", - "#text": self.intervention.legal.process_type.long_name, + "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/44382/{process_type.atom_id if process_type else None}", + "#text": process_type.long_name if process_type else None, }, "oneo:eingreifer": { "oneo:Eingreifer": { "oneo:art": { - "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1053/{self.intervention.responsible.handler.type.atom_id}", - "#text": self.intervention.responsible.handler.type.long_name, + "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1053/{handler.type.atom_id if handler.type else None}", + "#text": handler.type.long_name if handler.type else None, }, - "oneo:bemerkung": self.intervention.responsible.handler.detail, + "oneo:bemerkung": handler.detail if handler else None, } }, "oneo:erfasser": { @@ -212,8 +222,8 @@ class EgonGmlBuilder: "oneo:zulassung": { "oneo:Zulassungstermin": { "oneo:bauBeginn": payment_date, - "oneo:erlass": self.intervention.legal.registration_date.strftime(DEFAULT_DATE_FORMAT), - "oneo:rechtsKraft": self.intervention.legal.binding_date.strftime(DEFAULT_DATE_FORMAT), + "oneo:erlass": reg_date.strftime(DEFAULT_DATE_FORMAT) if reg_date else None, + "oneo:rechtsKraft": bind_date.strftime(DEFAULT_DATE_FORMAT) if bind_date else None, } }, "oneo:geometrie": { From 989d256521adb3d72bfbd57e0c7f0915694f6ea0 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Mon, 25 Apr 2022 13:28:51 +0200 Subject: [PATCH 13/15] HOTFIX: EGON sending via API * adds EGON message triggering on API payment changes --- api/utils/serializer/v1/intervention.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/utils/serializer/v1/intervention.py b/api/utils/serializer/v1/intervention.py index 1ce2d684..af13c4a2 100644 --- a/api/utils/serializer/v1/intervention.py +++ b/api/utils/serializer/v1/intervention.py @@ -132,6 +132,7 @@ class InterventionAPISerializerV1(AbstractModelAPISerializerV1, id__in=payments ) obj.payments.set(payments) + obj.send_data_to_egon() return obj def create_model_from_json(self, json_model, user): @@ -197,7 +198,7 @@ class InterventionAPISerializerV1(AbstractModelAPISerializerV1, obj.legal.save() obj.save() - obj.mark_as_edited(user) + obj.mark_as_edited(user, edit_comment="API update") celery_update_parcels.delay(obj.geometry.id) From 339f0746813f909b12be13cb3a1229acdf5eba49 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Mon, 25 Apr 2022 13:47:07 +0200 Subject: [PATCH 14/15] HOTFIX: API * hardens atom_id input to be integer or string compatible --- api/utils/serializer/v1/serializer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/api/utils/serializer/v1/serializer.py b/api/utils/serializer/v1/serializer.py index 23d1f692..9d3b9dfb 100644 --- a/api/utils/serializer/v1/serializer.py +++ b/api/utils/serializer/v1/serializer.py @@ -75,7 +75,10 @@ class AbstractModelAPISerializerV1(AbstractModelAPISerializer): Returns: """ - if json_str is None or len(json_str) == 0: + if json_str is None: + return None + json_str = str(json_str) + if len(json_str) == 0: return None code = KonovaCode.objects.get( atom_id=json_str, From 73c61e96f51e0211a0cd65afc1641d3f22a98766 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Wed, 27 Apr 2022 12:12:56 +0200 Subject: [PATCH 15/15] #156 Parcel WFS as geojson * refactors fetching of parcels via wfs from xml to json for easier and faster processing --- konova/models/geometry.py | 26 +++++++++++------- konova/utils/wfs/spatial.py | 54 ++++++++++++++++--------------------- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/konova/models/geometry.py b/konova/models/geometry.py index a71a2afa..283f8508 100644 --- a/konova/models/geometry.py +++ b/konova/models/geometry.py @@ -113,32 +113,38 @@ class Geometry(BaseResource): _now = timezone.now() underlying_parcels = [] for result in fetched_parcels: - fetched_parcel = result[typename] + parcel_properties = result["properties"] # There could be parcels which include the word 'Flur', # which needs to be deleted and just keep the numerical values ## THIS CAN BE REMOVED IN THE FUTURE, WHEN 'Flur' WON'T OCCUR ANYMORE! - flr_val = fetched_parcel["ave:flur"].replace("Flur ", "") + flr_val = parcel_properties["flur"].replace("Flur ", "") district = District.objects.get_or_create( - key=fetched_parcel["ave:kreisschl"], - name=fetched_parcel["ave:kreis"], + key=parcel_properties["kreisschl"], + name=parcel_properties["kreis"], )[0] municipal = Municipal.objects.get_or_create( - key=fetched_parcel["ave:gmdschl"], - name=fetched_parcel["ave:gemeinde"], + key=parcel_properties["gmdschl"], + name=parcel_properties["gemeinde"], district=district, )[0] parcel_group = ParcelGroup.objects.get_or_create( - key=fetched_parcel["ave:gemaschl"], - name=fetched_parcel["ave:gemarkung"], + key=parcel_properties["gemaschl"], + name=parcel_properties["gemarkung"], municipal=municipal, )[0] + flrstck_nnr = parcel_properties['flstnrnen'] + if not flrstck_nnr: + flrstck_nnr = None + flrstck_zhlr = parcel_properties['flstnrzae'] + if not flrstck_zhlr: + flrstck_zhlr = None parcel_obj = Parcel.objects.get_or_create( district=district, municipal=municipal, parcel_group=parcel_group, flr=flr_val, - flrstck_nnr=fetched_parcel['ave:flstnrnen'], - flrstck_zhlr=fetched_parcel['ave:flstnrzae'], + flrstck_nnr=flrstck_nnr, + flrstck_zhlr=flrstck_zhlr, )[0] parcel_obj.district = district parcel_obj.updated_on = _now diff --git a/konova/utils/wfs/spatial.py b/konova/utils/wfs/spatial.py index 8a7bf360..2f1452d6 100644 --- a/konova/utils/wfs/spatial.py +++ b/konova/utils/wfs/spatial.py @@ -5,11 +5,12 @@ Contact: michel.peltriaux@sgdnord.rlp.de Created on: 17.12.21 """ +import json from abc import abstractmethod +from json import JSONDecodeError from time import sleep import requests -import xmltodict from django.contrib.gis.db.models.functions import AsGML, Transform from requests.auth import HTTPDigestAuth @@ -115,7 +116,7 @@ class ParcelWFSFetcher(AbstractWFSFetcher): geometry_operation, filter_srid ) - _filter = f'{spatial_filter}' + _filter = f'{spatial_filter}' return _filter def get_features(self, @@ -139,7 +140,7 @@ class ParcelWFSFetcher(AbstractWFSFetcher): Returns: features (list): A list of returned features """ - features = [] + found_features = [] while start_index is not None: post_body = self._create_post_data( spatial_operator, @@ -155,19 +156,11 @@ class ParcelWFSFetcher(AbstractWFSFetcher): ) content = response.content.decode("utf-8") - content = xmltodict.parse(content) - collection = content.get( - "wfs:FeatureCollection", - {}, - ) - - # Check if collection is an exception and does not contain the requested data - if len(collection) == 0: - exception = content.get( - "ows:ExceptionReport", - {} - ) - if len(exception) > 0 and rerun_on_exception: + try: + # Check if collection is an exception and does not contain the requested data + content = json.loads(content) + except JSONDecodeError as e: + if rerun_on_exception: # Wait a second before another try sleep(1) self.get_features( @@ -177,22 +170,21 @@ class ParcelWFSFetcher(AbstractWFSFetcher): start_index, rerun_on_exception=False ) - - members = collection.get( - "wfs:member", - None, - ) - if members is not None: - if len(members) > 1: - # extend feature list with found list of new feature members - features += members else: - # convert single found feature member into list and extent feature list - features += [members] + e.msg += content + raise e + fetched_features = content.get( + "features", + {}, + ) - if collection.get("@next", None) is not None: - start_index += self.count - else: + found_features += fetched_features + + if len(fetched_features) < self.count: + # The response was not 'full', so we got everything to fetch start_index = None + else: + # If a 'full' response returned, there might be more to fetch. Increase the start_index! + start_index += self.count - return features + return found_features