Skip to content

Commit 2ca3058

Browse files
[Fixes #261] Add remote WMS importer handler (#263)
* [Fixes #261] Add remote WMS importer handler * Add handler in settings
1 parent 924b6f4 commit 2ca3058

File tree

17 files changed

+680
-42
lines changed

17 files changed

+680
-42
lines changed

importer/handlers/base.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,11 +255,12 @@ def get_ogr2ogr_task_group(
255255
"""
256256
return NotImplementedError
257257

258-
def delete_resource(self, instance):
258+
@staticmethod
259+
def delete_resource(instance):
259260
"""
260261
Base function to delete the resource with all the dependencies (example: dynamic model)
261262
"""
262-
return NotImplementedError
263+
return
263264

264265
def _get_execution_request_object(self, execution_id: str):
265266
return ExecutionRequest.objects.filter(exec_id=execution_id).first()
@@ -326,13 +327,15 @@ def rollback(
326327
def _create_geonode_resource_rollback(
327328
self, exec_id, istance_name=None, *args, **kwargs
328329
):
330+
from importer.orchestrator import orchestrator
329331
"""
330332
The handler will remove the resource from geonode
331333
"""
332334
logger.info(
333335
f"Rollback geonode step in progress for execid: {exec_id} resource created was: {istance_name}"
334336
)
335-
resource = ResourceBase.objects.filter(alternate__icontains=istance_name)
337+
_exec_obj = orchestrator.get_execution_object(exec_id)
338+
resource = ResourceBase.objects.filter(alternate__icontains=istance_name, owner=_exec_obj.user)
336339
if resource.exists():
337340
resource.delete()
338341

importer/handlers/common/raster.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,10 +370,11 @@ def overwrite_geonode_resource(
370370
resource_type: Dataset = Dataset,
371371
asset=None,
372372
):
373-
dataset = resource_type.objects.filter(alternate__icontains=alternate)
374-
373+
375374
_exec = self._get_execution_request_object(execution_id)
376375

376+
dataset = resource_type.objects.filter(alternate__icontains=alternate, owner=_exec.user)
377+
377378
_overwrite = _exec.input_params.get("overwrite_existing_layer", False)
378379
# if the layer exists, we just update the information of the dataset by
379380
# let it recreate the catalogue

importer/handlers/common/remote.py

Lines changed: 87 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ def extract_params_from_data(_data, action=None):
9191
"title": _data.pop("title", None),
9292
"url": _data.pop("url", None),
9393
"type": _data.pop("type", None),
94+
"overwrite_existing_layer": _data.pop("overwrite_existing_layer", False),
9495
}, _data
9596

9697
def import_resource(self, files: dict, execution_id: str, **kwargs) -> str:
@@ -110,28 +111,29 @@ def import_resource(self, files: dict, execution_id: str, **kwargs) -> str:
110111
try:
111112
params = _exec.input_params.copy()
112113
url = params.get("url")
113-
title = params.get("title", os.path.basename(urlparse(url).path))
114+
title = params.get("title", None) or os.path.basename(urlparse(url).path)
114115

115116
# start looping on the layers available
116117
layer_name = self.fixup_name(title)
117118

118119
should_be_overwritten = _exec.input_params.get("overwrite_existing_layer")
119120

121+
payload_alternate = params.get("remote_resource_id", None)
122+
120123
user_datasets = ResourceBase.objects.filter(
121-
owner=_exec.user, alternate=layer_name
124+
owner=_exec.user, alternate=payload_alternate or layer_name
122125
)
123126

124127
dataset_exists = user_datasets.exists()
125128

126-
if dataset_exists and should_be_overwritten:
127-
layer_name, alternate = (
128-
layer_name,
129-
user_datasets.first().alternate.split(":")[-1],
130-
)
131-
elif not dataset_exists:
132-
alternate = layer_name
133-
else:
134-
alternate = create_alternate(layer_name, execution_id)
129+
layer_name, alternate = self.generate_alternate(
130+
layer_name,
131+
execution_id,
132+
should_be_overwritten,
133+
payload_alternate,
134+
user_datasets,
135+
dataset_exists,
136+
)
135137

136138
import_orchestrator.apply_async(
137139
(
@@ -150,12 +152,32 @@ def import_resource(self, files: dict, execution_id: str, **kwargs) -> str:
150152
logger.error(e)
151153
raise e
152154

155+
def generate_alternate(
156+
self,
157+
layer_name,
158+
execution_id,
159+
should_be_overwritten,
160+
payload_alternate,
161+
user_datasets,
162+
dataset_exists,
163+
):
164+
if dataset_exists and should_be_overwritten:
165+
layer_name, alternate = (
166+
payload_alternate or layer_name,
167+
user_datasets.first().alternate.split(":")[-1],
168+
)
169+
elif not dataset_exists:
170+
alternate = payload_alternate or layer_name
171+
else:
172+
alternate = create_alternate(payload_alternate or layer_name, execution_id)
173+
return layer_name, alternate
174+
153175
def create_geonode_resource(
154176
self,
155177
layer_name: str,
156178
alternate: str,
157179
execution_id: str,
158-
resource_type: Dataset = ...,
180+
resource_type: ResourceBase = ResourceBase,
159181
asset=None,
160182
):
161183
"""
@@ -166,19 +188,12 @@ def create_geonode_resource(
166188
"""
167189
_exec = orchestrator.get_execution_object(execution_id)
168190
params = _exec.input_params.copy()
169-
subtype = params.get("type")
170191

171192
resource = resource_manager.create(
172193
None,
173-
resource_type=ResourceBase,
174-
defaults=dict(
175-
resource_type="dataset",
176-
subtype=subtype,
177-
sourcetype=SOURCE_TYPE_REMOTE,
178-
alternate=alternate,
179-
dirty_state=True,
180-
title=params.get("title", layer_name),
181-
owner=_exec.user,
194+
resource_type=resource_type,
195+
defaults=self.generate_resource_payload(
196+
layer_name, alternate, asset, _exec, None, **params
182197
),
183198
)
184199
resource_manager.set_thumbnail(None, instance=resource)
@@ -217,3 +232,53 @@ def create_resourcehandlerinfo(
217232
execution_request=execution_id,
218233
kwargs=kwargs.get("kwargs", {}) or kwargs,
219234
)
235+
236+
def generate_resource_payload(
237+
self, layer_name, alternate, asset, _exec, workspace, **kwargs
238+
):
239+
return dict(
240+
subtype=kwargs.get("type"),
241+
sourcetype=SOURCE_TYPE_REMOTE,
242+
alternate=alternate,
243+
dirty_state=True,
244+
title=kwargs.get("title", layer_name),
245+
owner=_exec.user,
246+
)
247+
248+
def overwrite_geonode_resource(
249+
self,
250+
layer_name: str,
251+
alternate: str,
252+
execution_id: str,
253+
resource_type: Dataset = ResourceBase,
254+
asset=None,
255+
):
256+
_exec = self._get_execution_request_object(execution_id)
257+
resource = resource_type.objects.filter(alternate__icontains=alternate, owner=_exec.user)
258+
259+
_overwrite = _exec.input_params.get("overwrite_existing_layer", False)
260+
# if the layer exists, we just update the information of the dataset by
261+
# let it recreate the catalogue
262+
if resource.exists() and _overwrite:
263+
resource = resource.first()
264+
265+
resource = resource_manager.update(
266+
resource.uuid, instance=resource
267+
)
268+
resource_manager.set_thumbnail(
269+
resource.uuid, instance=resource, overwrite=True
270+
)
271+
resource.refresh_from_db()
272+
return resource
273+
elif not resource.exists() and _overwrite:
274+
logger.warning(
275+
f"The dataset required {alternate} does not exists, but an overwrite is required, the resource will be created"
276+
)
277+
return self.create_geonode_resource(
278+
layer_name, alternate, execution_id, resource_type, asset
279+
)
280+
elif not resource.exists() and not _overwrite:
281+
logger.warning(
282+
"The resource does not exists, please use 'create_geonode_resource' to create one"
283+
)
284+
return

importer/handlers/common/serializer.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,19 @@ class Meta:
1313
"title",
1414
"type",
1515
"source",
16+
"overwrite_existing_layer"
1617
)
1718

18-
url = serializers.URLField(required=True)
19-
title = serializers.CharField(required=False)
20-
type = serializers.CharField(required=True)
19+
url = serializers.URLField(
20+
required=True, help_text="URL of the remote service / resource"
21+
)
22+
title = serializers.CharField(
23+
required=True, help_text="Title of the resource. Can be None or Empty"
24+
)
25+
type = serializers.CharField(
26+
required=True,
27+
help_text="Remote resource type, for example wms or 3dtiles. Is used by the handler to understand if can handle the resource",
28+
)
2129
source = serializers.CharField(required=False, default="upload")
30+
31+
overwrite_existing_layer = serializers.BooleanField(required=False, default=False)

importer/handlers/common/test_remote.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from importer.orchestrator import orchestrator
88
from geonode.base.populate_test_data import create_single_dataset
99
from geonode.resource.models import ExecutionRequest
10+
from geonode.base.models import ResourceBase
1011

1112

1213
class TestBaseRemoteResourceHandler(TestCase):
@@ -131,7 +132,7 @@ def test_create_geonode_resource(self):
131132
"layername",
132133
"layeralternate",
133134
execution_id=exec_id,
134-
resource_type="ResourceBase",
135+
resource_type=ResourceBase,
135136
asset=None,
136137
)
137138
self.assertIsNotNone(resource)

importer/handlers/common/vector.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from importer.orchestrator import orchestrator
3636
from django.db.models import Q
3737
import pyproj
38+
from geonode.geoserver.security import delete_dataset_cache, set_geowebcache_invalidate_cache
3839

3940
logger = logging.getLogger(__name__)
4041

@@ -631,16 +632,19 @@ def overwrite_geonode_resource(
631632
resource_type: Dataset = Dataset,
632633
asset=None,
633634
):
634-
dataset = resource_type.objects.filter(alternate__icontains=alternate)
635-
636635
_exec = self._get_execution_request_object(execution_id)
637636

637+
dataset = resource_type.objects.filter(alternate__icontains=alternate, owner=_exec.user)
638+
638639
_overwrite = _exec.input_params.get("overwrite_existing_layer", False)
639640
# if the layer exists, we just update the information of the dataset by
640641
# let it recreate the catalogue
641642
if dataset.exists() and _overwrite:
642643
dataset = dataset.first()
643644

645+
delete_dataset_cache(dataset.alternate)
646+
set_geowebcache_invalidate_cache(dataset.typename)
647+
644648
dataset = resource_manager.update(
645649
dataset.uuid, instance=dataset, files=asset.location
646650
)

importer/handlers/remote/serializers/__init__.py

Whitespace-only changes.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from rest_framework import serializers
2+
from importer.handlers.common.serializer import RemoteResourceSerializer
3+
4+
5+
class RemoteWMSSerializer(RemoteResourceSerializer):
6+
class Meta:
7+
model = RemoteResourceSerializer.Meta.model
8+
ref_name = "RemoteWMSSerializer"
9+
fields = RemoteResourceSerializer.Meta.fields + (
10+
"lookup",
11+
"bbox",
12+
"parse_remote_metadata",
13+
)
14+
15+
lookup = serializers.CharField(required=True)
16+
bbox = serializers.ListField(required=False)
17+
parse_remote_metadata = serializers.BooleanField(required=False, default=False)

importer/handlers/remote/tests/__init__.py

100644100755
File mode changed.

importer/handlers/remote/tests/test_3dtiles.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from importer.orchestrator import orchestrator
99
from geonode.base.populate_test_data import create_single_dataset
1010
from geonode.resource.models import ExecutionRequest
11+
from geonode.base.models import ResourceBase
1112

1213

1314
class TestRemoteTiles3DFileHandler(TestCase):
@@ -133,7 +134,7 @@ def test_create_geonode_resource_raise_error_if_url_is_not_reachabel(self):
133134
"layername",
134135
"layeralternate",
135136
execution_id=exec_id,
136-
resource_type="ResourceBase",
137+
resource_type=ResourceBase,
137138
asset=None,
138139
)
139140

@@ -153,7 +154,7 @@ def test_create_geonode_resource(self):
153154
"layername",
154155
"layeralternate",
155156
execution_id=exec_id,
156-
resource_type="ResourceBase",
157+
resource_type=ResourceBase,
157158
asset=None,
158159
)
159160
self.assertIsNotNone(resource)

0 commit comments

Comments
 (0)