-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* Fixes #200: Add XML file handler * Fixes #200: Remove import_metadata, collapse it to import_resource * Fixes #200: Remove unused import --------- Co-authored-by: Giovanni Allegri <[email protected]>
- Loading branch information
1 parent
085cbcc
commit 02bda68
Showing
13 changed files
with
312 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import logging | ||
from geonode.resource.enumerator import ExecutionRequestAction as exa | ||
from importer.handlers.base import BaseHandler | ||
from importer.handlers.xml.serializer import MetadataFileSerializer | ||
from importer.utils import ImporterRequestAction as ira | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class MetadataFileHandler(BaseHandler): | ||
""" | ||
Handler to import KML files into GeoNode data db | ||
It must provide the task_lists required to comple the upload | ||
""" | ||
|
||
ACTIONS = { | ||
exa.IMPORT.value: ( | ||
"start_import", | ||
"importer.import_resource" | ||
), | ||
ira.ROLLBACK.value: () | ||
} | ||
|
||
@staticmethod | ||
def has_serializer(_data) -> bool: | ||
return MetadataFileSerializer | ||
|
||
@property | ||
def supported_file_extension_config(self): | ||
return None | ||
|
||
@staticmethod | ||
def extract_params_from_data(_data, action=None): | ||
""" | ||
Remove from the _data the params that needs to save into the executionRequest object | ||
all the other are returned | ||
""" | ||
return { | ||
"dataset_title": _data.pop("dataset_title", None), | ||
"skip_existing_layers": _data.pop("skip_existing_layers", "False"), | ||
"overwrite_existing_layer": _data.pop("overwrite_existing_layer", "False"), | ||
"store_spatial_file": _data.pop("store_spatial_files", "True"), | ||
}, _data | ||
|
||
@staticmethod | ||
def perform_last_step(execution_id): | ||
pass | ||
|
||
def import_resource(self, files: dict, execution_id: str, **kwargs): | ||
pass | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from rest_framework.exceptions import APIException | ||
from rest_framework import status | ||
|
||
|
||
class InvalidXmlException(APIException): | ||
status_code = status.HTTP_400_BAD_REQUEST | ||
default_detail = "The xml provided provided is invalid" | ||
default_code = "invalid_xml" | ||
category = "importer" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import logging | ||
|
||
from django.shortcuts import get_object_or_404 | ||
from geonode.layers.models import Dataset | ||
from geonode.resource.enumerator import ExecutionRequestAction as exa | ||
from geonode.resource.manager import resource_manager | ||
from importer.handlers.common.metadata import MetadataFileHandler | ||
from importer.handlers.xml.exceptions import InvalidXmlException | ||
from importer.orchestrator import orchestrator | ||
from owslib.etree import etree as dlxml | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class XMLFileHandler(MetadataFileHandler): | ||
""" | ||
Handler to import KML files into GeoNode data db | ||
It must provide the task_lists required to comple the upload | ||
""" | ||
|
||
@staticmethod | ||
def can_handle(_data) -> bool: | ||
""" | ||
This endpoint will return True or False if with the info provided | ||
the handler is able to handle the file or not | ||
""" | ||
base = _data.get("base_file") | ||
if not base: | ||
return False | ||
return ( | ||
base.endswith(".xml") | ||
if isinstance(base, str) | ||
else base.name.endswith(".xml") | ||
) | ||
|
||
@staticmethod | ||
def is_valid(files, user=None): | ||
""" | ||
Define basic validation steps | ||
""" | ||
# calling base validation checks | ||
|
||
try: | ||
with open(files.get("base_file")) as _xml: | ||
dlxml.fromstring(_xml.read().encode()) | ||
except Exception as err: | ||
raise InvalidXmlException(f"Uploaded document is not XML or is invalid: {str(err)}") | ||
return True | ||
|
||
def import_resource(self, files: dict, execution_id: str, **kwargs): | ||
_exec = orchestrator.get_execution_object(execution_id) | ||
# getting the dataset | ||
alternate = _exec.input_params.get("dataset_title") | ||
dataset = get_object_or_404(Dataset, alternate=alternate) | ||
|
||
# retrieving the handler used for the dataset | ||
original_handler = orchestrator.load_handler( | ||
dataset.resourcehandlerinfo_set\ | ||
.first()\ | ||
.handler_module_path | ||
)() | ||
|
||
if original_handler.can_handle_xml_file: | ||
original_handler.handle_xml_file(dataset, _exec) | ||
else: | ||
_path = _exec.input_params.get("files", {}).get("xml_file", _exec.input_params.get("base_file", {})) | ||
resource_manager.update( | ||
None, | ||
instance=dataset, | ||
xml_file=_path, | ||
metadata_uploaded=True if _path else False, | ||
vals={"dirty_state": True}, | ||
) | ||
dataset.refresh_from_db() | ||
|
||
orchestrator.evaluate_execution_progress(execution_id, handler_module_path=str(self)) | ||
return | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from rest_framework import serializers | ||
from dynamic_rest.serializers import DynamicModelSerializer | ||
from geonode.upload.models import Upload | ||
|
||
|
||
class MetadataFileSerializer(DynamicModelSerializer): | ||
class Meta: | ||
ref_name = "MetadataFileSerializer" | ||
model = Upload | ||
view_name = "importer_upload" | ||
fields = ( | ||
"dataset_title", | ||
"base_file" | ||
) | ||
|
||
base_file = serializers.FileField() | ||
dataset_title = serializers.CharField(required=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
from django.conf import settings | ||
from django.contrib.auth import get_user_model | ||
from django.test import TestCase | ||
from geonode.base.populate_test_data import create_single_dataset | ||
from importer import project_dir | ||
from importer.models import ResourceHandlerInfo | ||
from importer.orchestrator import orchestrator | ||
from importer.handlers.xml.exceptions import InvalidXmlException | ||
from importer.handlers.xml.handler import XMLFileHandler | ||
|
||
|
||
class TestXMLFileHandler(TestCase): | ||
databases = ("default", "datastore") | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
super().setUpClass() | ||
cls.handler = XMLFileHandler() | ||
cls.valid_xml = f"{settings.PROJECT_ROOT}/base/fixtures/test_xml.xml" | ||
cls.invalid_xml = f"{project_dir}/tests/fixture/invalid.gpkg" | ||
cls.user, _ = get_user_model().objects.get_or_create(username="admin") | ||
cls.invalid_files = {"base_file": cls.invalid_xml, 'xml_file': cls.invalid_xml} | ||
cls.valid_files = {"base_file": cls.valid_xml, 'xml_file': cls.valid_xml} | ||
cls.owner = get_user_model().objects.first() | ||
cls.layer = create_single_dataset(name="extruded_polygon", owner=cls.owner) | ||
|
||
def test_task_list_is_the_expected_one(self): | ||
expected = ( | ||
"start_import", | ||
"importer.import_resource", | ||
) | ||
self.assertEqual(len(self.handler.ACTIONS["import"]), 2) | ||
self.assertTupleEqual(expected, self.handler.ACTIONS["import"]) | ||
|
||
def test_is_valid_should_raise_exception_if_the_xml_is_invalid(self): | ||
with self.assertRaises(InvalidXmlException) as _exc: | ||
self.handler.is_valid(files=self.invalid_files) | ||
|
||
self.assertIsNotNone(_exc) | ||
self.assertTrue("Uploaded document is not XML or is invalid" in str(_exc.exception.detail)) | ||
|
||
def test_is_valid_should_pass_with_valid_xml(self): | ||
self.handler.is_valid(files=self.valid_files) | ||
|
||
def test_can_handle_should_return_true_for_xml(self): | ||
actual = self.handler.can_handle(self.valid_files) | ||
self.assertTrue(actual) | ||
|
||
def test_can_handle_should_return_false_for_other_files(self): | ||
actual = self.handler.can_handle({"base_file": "random.file"}) | ||
self.assertFalse(actual) | ||
|
||
def test_can_successfully_import_metadata_file(self): | ||
exec_id = orchestrator.create_execution_request( | ||
user=get_user_model().objects.first(), | ||
func_name="funct1", | ||
step="step", | ||
input_params={ | ||
"files": self.valid_files, | ||
"dataset_title": self.layer.alternate, | ||
"skip_existing_layer": True, | ||
"handler_module_path": str(self.handler), | ||
}, | ||
) | ||
ResourceHandlerInfo.objects.create( | ||
resource=self.layer, | ||
handler_module_path="importer.handlers.shapefile.handler.ShapeFileHandler", | ||
) | ||
|
||
self.assertEqual(self.layer.title, "extruded_polygon") | ||
|
||
self.handler.import_resource({}, str(exec_id)) | ||
|
||
self.layer.refresh_from_db() | ||
self.assertEqual(self.layer.title, "test_dataset") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.