Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

micka.soap: patch_after_wfst #353

Merged
merged 10 commits into from
May 5, 2021
30 changes: 25 additions & 5 deletions src/geoserver/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def patch_feature_type(geoserver_workspace, feature_type_name, *, title=None, de
if description:
ftype['abstract'] = description
if bbox:
ftype['nativeBoundingBox'] = bbox
ftype['nativeBoundingBox'] = bbox_to_native_bbox(bbox)

ftype = {k: v for k, v in ftype.items() if v is not None}
body = {
Expand Down Expand Up @@ -500,12 +500,11 @@ def delete_wms_layer(geoserver_workspace, layer, auth):


def patch_wms_layer(geoserver_workspace, layer, *, auth, bbox):
wms_layer = {
"enabled": True,
}
wms_layer = get_wms_layer(geoserver_workspace, layer, auth=auth)
jirik marked this conversation as resolved.
Show resolved Hide resolved
if bbox:
wms_layer['nativeBoundingBox'] = bbox
wms_layer['nativeBoundingBox'] = bbox_to_native_bbox(bbox)
jirik marked this conversation as resolved.
Show resolved Hide resolved
wms_layer['nativeCRS'] = 'EPSG:3857'
# automatically recalculates also 'latLonBoundingBox'
r = requests.put(urljoin(GS_REST_WORKSPACES,
f'{geoserver_workspace}/wmslayers/{layer}'),
data=json.dumps({
Expand All @@ -518,6 +517,17 @@ def patch_wms_layer(geoserver_workspace, layer, *, auth, bbox):
r.raise_for_status()


def get_wms_layer(geoserver_workspace, layer, *, auth):
r = requests.get(urljoin(GS_REST_WORKSPACES,
f'{geoserver_workspace}/wmslayers/{layer}'),
headers=headers_json,
auth=auth,
timeout=5,
)
r.raise_for_status()
return r.json()['wmsLayer']


def ensure_workspace(geoserver_workspace, auth=None):
auth = auth or GS_AUTH
all_workspaces = get_all_workspaces(auth)
Expand Down Expand Up @@ -792,3 +802,13 @@ def get_feature_type(
)
r.raise_for_status()
return r.json()['featureType']


def bbox_to_native_bbox(bbox):
return {
"minx": bbox[0],
"miny": bbox[1],
"maxx": bbox[2],
"maxy": bbox[3],
"crs": "EPSG:3857",
}
51 changes: 51 additions & 0 deletions src/layman/common/bbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,41 @@ def contains_bbox(bbox1, bbox2):
and bbox1[0] <= bbox2[0] and bbox2[2] <= bbox1[2] and bbox1[1] <= bbox2[1] and bbox2[3] <= bbox1[3]


def intersects(bbox1, bbox2):
jirik marked this conversation as resolved.
Show resolved Hide resolved
return not is_empty(bbox1) and not is_empty(bbox2) \
and bbox1[0] <= bbox2[2] and bbox1[2] >= bbox2[0] and bbox1[1] <= bbox2[3] and bbox1[3] >= bbox2[1]


def get_intersection(bbox1, bbox2):
intersection = [None] * 4
if intersects(bbox1, bbox2):
if bbox1[0] > bbox2[0]:
intersection[0] = bbox1[0]
else:
intersection[0] = bbox2[0]
if bbox1[1] > bbox2[1]:
intersection[1] = bbox1[1]
else:
intersection[1] = bbox2[1]
if bbox1[2] < bbox2[2]:
intersection[2] = bbox1[2]
else:
intersection[2] = bbox2[2]
if bbox1[3] < bbox2[3]:
intersection[3] = bbox1[3]
else:
intersection[3] = bbox2[3]
return intersection


def has_area(bbox):
return not is_empty(bbox) and bbox[0] != bbox[2] and bbox[1] != bbox[3]


def get_area(bbox):
return (bbox[2] - bbox[0]) * (bbox[3] - bbox[1])


def ensure_bbox_with_area(bbox, no_area_padding):
result = bbox
if not has_area(bbox):
Expand All @@ -46,3 +77,23 @@ def transform(bbox, epsg_from=4326, epsg_to=3857):
params = bbox + (epsg_from, epsg_to,)
result = db_util.run_query(query, params)[0]
return result


def are_similar(bbox1, bbox2, *, no_area_bbox_padding=None, limit=0.95):
if not has_area(bbox1):
assert no_area_bbox_padding is not None and no_area_bbox_padding > 0
bbox1 = ensure_bbox_with_area(bbox1, no_area_bbox_padding)
if not has_area(bbox2):
assert no_area_bbox_padding is not None and no_area_bbox_padding > 0
bbox2 = ensure_bbox_with_area(bbox2, no_area_bbox_padding)
isect = get_intersection(bbox1, bbox2)
if is_empty(isect):
return False

a_area = get_area(bbox1)
b_area = get_area(bbox2)
i_area = get_area(isect)

similarity = i_area / a_area * i_area / b_area
# current_app.logger.info(f"a={a}, b={b}, similarity={similarity}")
return similarity >= limit
13 changes: 13 additions & 0 deletions src/layman/common/bbox_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ def test_contains_bbox(bbox1, bbox2, expected_result):
assert bbox_util.contains_bbox(bbox1, bbox2) == expected_result


@pytest.mark.parametrize('bbox1, bbox2, expected_result', [
((1, 1, 4, 4, ), (2, 2, 3, 3, ), True),
((1, 1, 4, 4, ), (1, 1, 4, 4, ), True),
((1, 1, 4, 4, ), (1, 1, 4, 5, ), True),
((1, 1, 4, 4, ), (4, 4, 5, 5, ), True),
((1, 1, 4, 4, ), (5, 5, 6, 6, ), False),
((1, 1, 4, 4, ), (None, None, None, None, ), False),
((None, None, None, None, ), (1, 1, 4, 4, ), False),
])
def test_intersects_bbox(bbox1, bbox2, expected_result):
assert bbox_util.intersects(bbox1, bbox2) == expected_result


@pytest.mark.parametrize('bbox, expected_result', [
((1, 1, 4, 4, ), True),
((1, 1, 1, 3, ), False),
Expand Down
50 changes: 4 additions & 46 deletions src/layman/common/metadata.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import json
from layman import settings
from layman.common import bbox as bbox_util
from layman.util import get_publication_types

PUBL_TYPE_DEF_KEY = __name__
Expand All @@ -10,18 +12,8 @@ def get_syncable_prop_names(publ_type):
return prop_names


def extent_equals(a, b, limit=0.95):
isect = _get_extent_intersetion(a, b)
if _is_extent_empty(isect):
return False

a_area = _get_extent_area(a)
b_area = _get_extent_area(b)
i_area = _get_extent_area(isect)

similarity = i_area / a_area * i_area / b_area
# current_app.logger.info(f"a={a}, b={b}, similarity={similarity}")
return similarity >= limit
def extent_equals(a, b):
return bbox_util.are_similar(a, b, no_area_bbox_padding=settings.NO_AREA_BBOX_PADDING, limit=0.95)


PROPERTIES = {
Expand Down Expand Up @@ -142,40 +134,6 @@ def strip_capabilities_and_layers_params(url):
return strip_params_from_url(url, ['SERVICE', 'REQUEST', 'VERSION', 'LAYERS'])


def _is_extent_empty(e):
return any((c is None for c in e))


def _get_extent_area(e):
return (e[2] - e[0]) * (e[3] - e[1])


def _get_extent_intersetion(a, b):
intersection = [None] * 4
if _extent_intersects(a, b):
if a[0] > b[0]:
intersection[0] = a[0]
else:
intersection[0] = b[0]
if a[1] > b[1]:
intersection[1] = a[1]
else:
intersection[1] = b[1]
if a[2] < b[2]:
intersection[2] = a[2]
else:
intersection[2] = b[2]
if a[3] < b[3]:
intersection[3] = a[3]
else:
intersection[3] = b[3]
return intersection


def _extent_intersects(a, b):
return a[0] <= b[2] and a[2] >= b[0] and a[1] <= b[3] and a[3] >= b[1]


def transform_metadata_props_to_comparison(all_props):
prop_names = sorted(list(set(pn for po in all_props.values() for pn in po.keys())))
sources = {
Expand Down
18 changes: 18 additions & 0 deletions src/layman/geoserver_proxy_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from geoserver.util import get_layer_thumbnail, get_square_bbox
from layman import app, settings, util as layman_util
from layman.common import bbox as bbox_util
from layman.layer import db, util as layer_util
from layman.layer.filesystem import thumbnail
from layman.layer.geoserver import wfs as geoserver_wfs
Expand Down Expand Up @@ -295,6 +296,8 @@ def wfs_post(workspace, attr_names_list, data_xml):
data_xml = data_wfs.get_wfs11_insert_polygon_new_attr(username, layername, attr_names10)
wfs_post(username, [(layername, attr_names10)], data_xml)

time.sleep(5)

client_util.delete_workspace_layer(username, layername, headers=headers)
client_util.delete_workspace_layer(username, layername2, headers=headers)

Expand Down Expand Up @@ -364,6 +367,8 @@ def do_test(wfs_query, attribute_names):
data_xml = data_wfs.get_wfs20_update_points_new_attr(username, layername1, attr_names)
do_test(data_xml, attr_names)

time.sleep(5)

client_util.delete_workspace_layer(username, layername1, headers=headers1)


Expand All @@ -375,6 +380,19 @@ def assert_all_sources_bbox(workspace, layer, expected_bbox):
test_util.assert_wfs_bbox(workspace, layer, expected_bbox)
test_util.assert_wms_bbox(workspace, layer, expected_bbox)

with app.app_context():
expected_bbox_4326 = bbox_util.transform(expected_bbox, 3857, 4326, )
md_comparison = client_util.get_workspace_layer_metadata_comparison(workspace, layer)
csw_prefix = settings.CSW_PROXY_URL
csw_src_key = client_util.get_source_key_from_metadata_comparison(md_comparison, csw_prefix)
assert csw_src_key is not None
prop_key = 'extent'
md_props = md_comparison['metadata_properties']
assert md_props[prop_key]['equal'] is True
assert md_props[prop_key]['equal_or_null'] is True
csw_bbox_4326 = tuple(md_props[prop_key]['values'][csw_src_key])
test_util.assert_same_bboxes(expected_bbox_4326, csw_bbox_4326, 0.001)


@pytest.mark.parametrize('style_file, thumbnail_style_postfix', [
(None, '_sld'),
Expand Down
24 changes: 7 additions & 17 deletions src/layman/layer/geoserver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from layman.http import LaymanError
from layman import settings, util as layman_util
from layman.common import bbox as bbox_util, geoserver as gs_common, empty_method
from layman.layer import LAYER_TYPE, db as db_source
from layman.layer import LAYER_TYPE
from layman.layer.qgis import wms as qgis_wms
from . import wms

Expand Down Expand Up @@ -108,25 +108,15 @@ def set_security_rules(workspace, layer, access_rights, auth, geoserver_workspac
gs_util.ensure_layer_security_roles(geoserver_workspace, layer, security_write_roles, 'w', auth)


def bbox_to_native_bbox(bbox):
return {
"minx": bbox[0],
"miny": bbox[1],
"maxx": bbox[2],
"maxy": bbox[3],
"crs": "EPSG:3857",
}


def get_default_native_bbox():
return bbox_to_native_bbox(settings.LAYMAN_DEFAULT_OUTPUT_BBOX)
def get_layer_bbox(workspace, layer):
db_bbox = layman_util.get_publication_info(workspace, LAYER_TYPE, layer, context={'keys': ['bounding_box']})['bounding_box']
# GeoServer is not working good with degradeted bbox
return bbox_util.ensure_bbox_with_area(db_bbox, settings.NO_AREA_BBOX_PADDING) if not bbox_util.is_empty(db_bbox) else settings.LAYMAN_DEFAULT_OUTPUT_BBOX


def get_layer_native_bbox(workspace, layer):
db_bbox = layman_util.get_publication_info(workspace, LAYER_TYPE, layer, context={'keys': ['bounding_box']})['bounding_box']
# GeoServer is not working good with degradeted bbox
bbox = bbox_util.ensure_bbox_with_area(db_bbox, settings.NO_AREA_BBOX_PADDING) if not bbox_util.is_empty(db_bbox) else settings.LAYMAN_DEFAULT_OUTPUT_BBOX
return bbox_to_native_bbox(bbox)
bbox = get_layer_bbox(workspace, layer)
return gs_util.bbox_to_native_bbox(bbox)


def publish_layer_from_db(workspace, layername, description, title, access_rights, geoserver_workspace=None):
Expand Down
2 changes: 1 addition & 1 deletion src/layman/layer/geoserver/wfs_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def patch_after_wfst(
if self.is_aborted():
raise AbortedException

bbox = geoserver.get_layer_native_bbox(workspace, layer)
bbox = geoserver.get_layer_bbox(workspace, layer)
gs_util.patch_feature_type(workspace, layer, auth=settings.LAYMAN_GS_AUTH, bbox=bbox)
wfs.clear_cache(workspace)

Expand Down
2 changes: 1 addition & 1 deletion src/layman/layer/geoserver/wms_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def patch_after_wfst(
if self.is_aborted():
raise AbortedException

bbox = geoserver.get_layer_native_bbox(workspace, layer)
bbox = geoserver.get_layer_bbox(workspace, layer)
geoserver_workspace = wms.get_geoserver_workspace(workspace)
style_type = layman_util.get_publication_info(workspace, LAYER_TYPE, layer, context={'keys': ['style_type'], })['style_type']
if style_type == 'sld':
Expand Down
18 changes: 7 additions & 11 deletions src/layman/layer/micka/csw.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from layman.common.filesystem.uuid import get_publication_uuid_file
from layman.common.micka import util as common_util
from layman.common import language as common_language, empty_method, empty_method_returns_none
from layman.common import language as common_language, empty_method, empty_method_returns_none, bbox as bbox_util
from layman.layer.filesystem.uuid import get_layer_uuid
from layman.layer import db
from layman.layer.geoserver import wms
Expand Down Expand Up @@ -114,19 +114,15 @@ def csw_insert(workspace, layername):

def get_template_path_and_values(workspace, layername, http_method=None):
assert http_method in ['post', 'patch']
wmsi = wms.get_wms_proxy(workspace)
wms_layer = wmsi.contents.get(layername) if wmsi else None
publ_info = get_publication_info(workspace, LAYER_TYPE, layername, context={
'keys': ['title'],
'keys': ['title', 'bounding_box', 'description'],
})
title = publ_info['title']

if wms_layer:
abstract = wms_layer.abstract
extent = wms_layer.boundingBoxWGS84
else:
abstract = None
extent = [-180, -90, 180, 90]
abstract = publ_info.get('description')
bbox_3857 = publ_info.get('bounding_box')
if bbox_util.is_empty(bbox_3857):
bbox_3857 = settings.LAYMAN_DEFAULT_OUTPUT_BBOX
extent = bbox_util.transform(tuple(bbox_3857), epsg_from=3857, epsg_to=4326)

uuid_file_path = get_publication_uuid_file(LAYER_TYPE, workspace, layername)
publ_datetime = datetime.fromtimestamp(os.path.getmtime(uuid_file_path))
Expand Down
26 changes: 26 additions & 0 deletions src/layman/layer/micka/soap_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from celery.utils.log import get_task_logger

from layman.celery import AbortedException
from layman import celery_app
from . import soap

logger = get_task_logger(__name__)


@celery_app.task(
name='layman.layer.micka.soap.patch_after_wfst',
bind=True,
base=celery_app.AbortableTask
)
def patch_after_wfst(
self,
workspace,
layer,
):
if self.is_aborted():
raise AbortedException

soap.patch_layer(workspace, layer, metadata_properties_to_refresh=['extent'])

if self.is_aborted():
raise AbortedException
6 changes: 3 additions & 3 deletions src/layman/layer/rest_test_filled_template.xml
Original file line number Diff line number Diff line change
Expand Up @@ -245,16 +245,16 @@
<gmd:geographicElement>
<gmd:EX_GeographicBoundingBox>
<gmd:westBoundLongitude>
<gco:Decimal>-179.9999999999996</gco:Decimal>
<gco:Decimal>-180.0</gco:Decimal>
</gmd:westBoundLongitude>
<gmd:eastBoundLongitude>
<gco:Decimal>180</gco:Decimal>
</gmd:eastBoundLongitude>
<gmd:southBoundLatitude>
<gco:Decimal>-85.60903777459771</gco:Decimal>
<gco:Decimal>-85.6090377745977</gco:Decimal>
</gmd:southBoundLatitude>
<gmd:northBoundLatitude>
<gco:Decimal>83.64512999999998</gco:Decimal>
<gco:Decimal>83.64513</gco:Decimal>
</gmd:northBoundLatitude>
</gmd:EX_GeographicBoundingBox>
</gmd:geographicElement>
Expand Down
Loading