Z-axis geometry upload fix
* adds clamping of 3D geometries to 2D geometries if uploaded using the map importer * extends tests for payment-document linkage * fixes bug in team-admin selection where autocomplete could not be resolved properly
This commit is contained in:
		
							parent
							
								
									814f35c426
								
							
						
					
					
						commit
						b0f9ee4ac0
					
				@ -11,7 +11,7 @@ from django.core.exceptions import ObjectDoesNotExist
 | 
				
			|||||||
from django.urls import reverse
 | 
					from django.urls import reverse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from compensation.models import Payment, EcoAccountDeduction
 | 
					from compensation.models import Payment, EcoAccountDeduction
 | 
				
			||||||
from intervention.models import Intervention
 | 
					from intervention.models import Intervention, InterventionDocument
 | 
				
			||||||
from konova.settings import ETS_GROUP, ZB_GROUP
 | 
					from konova.settings import ETS_GROUP, ZB_GROUP
 | 
				
			||||||
from konova.tests.test_views import BaseWorkflowTestCase
 | 
					from konova.tests.test_views import BaseWorkflowTestCase
 | 
				
			||||||
from user.models import UserActionLogEntry, UserAction
 | 
					from user.models import UserActionLogEntry, UserAction
 | 
				
			||||||
@ -153,13 +153,16 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
 | 
				
			|||||||
        payment = Payment.objects.create(amount=10.00, due_on=None, comment="No due date because test")
 | 
					        payment = Payment.objects.create(amount=10.00, due_on=None, comment="No due date because test")
 | 
				
			||||||
        self.intervention.payments.add(payment)
 | 
					        self.intervention.payments.add(payment)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Since there is a payment, we need to add a dummy document (mocking a legal document for payment info)
 | 
				
			||||||
 | 
					        document = self.create_dummy_document(InterventionDocument, self.intervention)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Run request again
 | 
					        # Run request again
 | 
				
			||||||
        self.client_user.post(check_url, post_data)
 | 
					        self.client_user.post(check_url, post_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Update intervention from db
 | 
					        # Update intervention from db
 | 
				
			||||||
        self.intervention.refresh_from_db()
 | 
					        self.intervention.refresh_from_db()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # We expect the intervention to be checked now and contains the proper data
 | 
					        # We expect the intervention to be checked now and contain the proper data
 | 
				
			||||||
        # Attention: We check the timestamp only on the date, not the time, since the microseconds delay would result
 | 
					        # Attention: We check the timestamp only on the date, not the time, since the microseconds delay would result
 | 
				
			||||||
        # in an unwanted assertion error
 | 
					        # in an unwanted assertion error
 | 
				
			||||||
        checked = self.intervention.checked
 | 
					        checked = self.intervention.checked
 | 
				
			||||||
@ -209,6 +212,9 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
 | 
				
			|||||||
        payment = Payment.objects.create(amount=10.00, due_on=None, comment="No due date because test")
 | 
					        payment = Payment.objects.create(amount=10.00, due_on=None, comment="No due date because test")
 | 
				
			||||||
        self.intervention.payments.add(payment)
 | 
					        self.intervention.payments.add(payment)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Since there is a payment, we need to add a dummy document (mocking a legal document for payment info)
 | 
				
			||||||
 | 
					        document = self.create_dummy_document(InterventionDocument, self.intervention)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Run request again
 | 
					        # Run request again
 | 
				
			||||||
        self.client_user.post(record_url, post_data)
 | 
					        self.client_user.post(record_url, post_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,7 @@ import json
 | 
				
			|||||||
from django.contrib.gis import gdal
 | 
					from django.contrib.gis import gdal
 | 
				
			||||||
from django.contrib.gis.forms import MultiPolygonField
 | 
					from django.contrib.gis.forms import MultiPolygonField
 | 
				
			||||||
from django.contrib.gis.geos import MultiPolygon, Polygon
 | 
					from django.contrib.gis.geos import MultiPolygon, Polygon
 | 
				
			||||||
 | 
					from django.contrib.gis.geos.prototypes.io import WKTWriter
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from konova.forms.base_form import BaseForm
 | 
					from konova.forms.base_form import BaseForm
 | 
				
			||||||
@ -74,9 +75,21 @@ class SimpleGeomForm(BaseForm):
 | 
				
			|||||||
        # this case)
 | 
					        # this case)
 | 
				
			||||||
        features = []
 | 
					        features = []
 | 
				
			||||||
        features_json = geom.get("features", [])
 | 
					        features_json = geom.get("features", [])
 | 
				
			||||||
 | 
					        accepted_ogr_types = [
 | 
				
			||||||
 | 
					            "Polygon",
 | 
				
			||||||
 | 
					            "Polygon25D",
 | 
				
			||||||
 | 
					            "MultiPolygon",
 | 
				
			||||||
 | 
					            "MultiPolygon25D",
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
        for feature in features_json:
 | 
					        for feature in features_json:
 | 
				
			||||||
            g = gdal.OGRGeometry(json.dumps(feature.get("geometry", feature)), srs=DEFAULT_SRID_RLP)
 | 
					            feature_geom = json.dumps(feature.get("geometry", feature))
 | 
				
			||||||
            if g.geom_type not in ["Polygon", "MultiPolygon"]:
 | 
					            g = gdal.OGRGeometry(feature_geom, srs=DEFAULT_SRID_RLP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            flatten_geometry = g.coord_dim > 2
 | 
				
			||||||
 | 
					            if flatten_geometry:
 | 
				
			||||||
 | 
					                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("geom", _("Only surfaces allowed. Points or lines must be buffered."))
 | 
				
			||||||
                is_valid = False
 | 
					                is_valid = False
 | 
				
			||||||
                return is_valid
 | 
					                return is_valid
 | 
				
			||||||
@ -131,3 +144,13 @@ class SimpleGeomForm(BaseForm):
 | 
				
			|||||||
        # Start the parcel update procedure in a background process
 | 
					        # Start the parcel update procedure in a background process
 | 
				
			||||||
        celery_update_parcels.delay(geometry.id)
 | 
					        celery_update_parcels.delay(geometry.id)
 | 
				
			||||||
        return geometry
 | 
					        return geometry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __flatten_geom_to_2D(self, geom):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Enforces a given OGRGeometry from higher dimensions into 2D
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        wkt_w = WKTWriter(dim=2)
 | 
				
			||||||
 | 
					        g_wkt = wkt_w.write(geom.geos).decode("utf-8")
 | 
				
			||||||
 | 
					        geom = gdal.OGRGeometry(g_wkt)
 | 
				
			||||||
 | 
					        return geom
 | 
				
			||||||
 | 
				
			|||||||
@ -115,6 +115,19 @@ class BaseTestCase(TestCase):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        return f"{prefix}{generate_random_string(3, True)}"
 | 
					        return f"{prefix}{generate_random_string(3, True)}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_dummy_document(self, DocumentModel, instance):
 | 
				
			||||||
 | 
					        """ Creates a document db entry which can be used for tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        doc = DocumentModel.objects.create(
 | 
				
			||||||
 | 
					            title="TEST_doc",
 | 
				
			||||||
 | 
					            comment="",
 | 
				
			||||||
 | 
					            file=None,
 | 
				
			||||||
 | 
					            date_of_creation="1970-01-01",
 | 
				
			||||||
 | 
					            instance=instance,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return doc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_dummy_intervention(self):
 | 
					    def create_dummy_intervention(self):
 | 
				
			||||||
        """ Creates an intervention which can be used for tests
 | 
					        """ Creates an intervention which can be used for tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -17,15 +17,15 @@ class TeamAdminAutocomplete(Select2QuerySetView):
 | 
				
			|||||||
    def get_queryset(self):
 | 
					    def get_queryset(self):
 | 
				
			||||||
        if self.request.user.is_anonymous:
 | 
					        if self.request.user.is_anonymous:
 | 
				
			||||||
            return User.objects.none()
 | 
					            return User.objects.none()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        qs = User.objects.filter(
 | 
					        qs = User.objects.filter(
 | 
				
			||||||
            id__in=self.forwarded.get("members", [])
 | 
					            id__in=self.forwarded.get("members", [])
 | 
				
			||||||
        ).exclude(
 | 
					        ).exclude(
 | 
				
			||||||
            id__in=self.forwarded.get("admins", [])
 | 
					            id__in=self.forwarded.get("admins", [])
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        if self.q:
 | 
					        if self.q:
 | 
				
			||||||
            # Due to privacy concerns only a full username match will return the proper user entry
 | 
					 | 
				
			||||||
            qs = qs.filter(
 | 
					            qs = qs.filter(
 | 
				
			||||||
                name__icontains=self.q
 | 
					                username__icontains=self.q
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        qs = qs.order_by(
 | 
					        qs = qs.order_by(
 | 
				
			||||||
            "username"
 | 
					            "username"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user