diff --git a/geonode/base/tests.py b/geonode/base/tests.py index 31681475624..f419e2da02a 100644 --- a/geonode/base/tests.py +++ b/geonode/base/tests.py @@ -27,6 +27,7 @@ from unittest.mock import patch, Mock from guardian.shortcuts import assign_perm +from django.utils.module_loading import import_string from django.db.utils import IntegrityError, OperationalError from django.core.exceptions import ObjectDoesNotExist from django.conf import settings @@ -57,6 +58,8 @@ HierarchicalKeyword, ResourceBase, MenuPlaceholder, + License, + Group, Menu, MenuItem, Configuration, @@ -1244,6 +1247,14 @@ def test_keyword_raise_db_error(self, add_root_mocked): ) +def _cache_less_call_storers(instance, custom={}): + storer_module_path = settings.METADATA_STORERS if hasattr(settings, "METADATA_STORERS") else [] + storers = [import_string(storer_path) for storer_path in storer_module_path] + for storer in storers: + storer(instance, custom) + return instance + + class TestRegions(GeoNodeBaseTestSupport): def setUp(self): self.dataset_inside_region = GEOSGeometry( @@ -1281,16 +1292,38 @@ def test_region_assignment_for_extent(self): region.is_assignable_to_geom(self.dataset_outside_region), "Extent outside a region should be assigned" ) - @override_settings(METADATA_STORERS=["geonode.resource.regions_storer.spatial_predicate_region_assignor"]) + @patch("geonode.resource.utils.call_storers", _cache_less_call_storers) def test_regions_are_assigned_if_handler_is_used(self): - dataset = resource_manager.create( - None, - resource_type=Dataset, - defaults=dict(owner=get_user_model().objects.first(), title="test_region_dataset", is_approved=True), - ) - self.assertTrue(dataset.regions.exists()) - self.assertEqual(1, dataset.regions.count()) - self.assertEqual("Global", dataset.regions.first().name) + with override_settings(METADATA_STORERS=["geonode.resource.regions_storer.spatial_predicate_region_assignor"]): + dataset = resource_manager.create( + None, + resource_type=Dataset, + defaults=dict(owner=get_user_model().objects.first(), title="test_region_dataset", is_approved=True), + ) + self.assertTrue(dataset.regions.exists()) + self.assertEqual(1, dataset.regions.count()) + self.assertEqual("Global", dataset.regions.first().name) + + +class TestMetadataStorer(GeoNodeBaseTestSupport): + + @patch("geonode.resource.utils.call_storers", _cache_less_call_storers) + def test_create_passing_custom_to_post_save(self): + + with override_settings(METADATA_STORERS=["geonode.resource.metadata_storer.store_metadata"]): + User = get_user_model() + user = User.objects.create(username="test", email="test@test.com") + license = License.objects.all().first() + group = Group.objects.all().first() + dataset = resource_manager.create( + str(uuid4()), + resource_type=Dataset, + defaults=dict(owner=user, title="test"), + custom=dict(group=group.pk, license=license), + ) + self.assertIsNotNone(dataset.license) + self.assertIsNotNone(dataset.group) + self.assertEqual(group.pk, dataset.group.pk) class LinkedResourcesTest(GeoNodeBaseTestSupport): diff --git a/geonode/resource/manager.py b/geonode/resource/manager.py index c196feddb67..ef837716a1d 100644 --- a/geonode/resource/manager.py +++ b/geonode/resource/manager.py @@ -313,7 +313,9 @@ def delete(self, uuid: str, /, instance: ResourceBase = None) -> int: ResourceBase.objects.filter(uuid=uuid).delete() return 0 - def create(self, uuid: str, /, resource_type: typing.Optional[object] = None, defaults: dict = {}) -> ResourceBase: + def create( + self, uuid: str, /, resource_type: typing.Optional[object] = None, defaults: dict = {}, *args, **kwargs + ) -> ResourceBase: if resource_type.objects.filter(uuid=uuid).exists(): return resource_type.objects.filter(uuid=uuid).get() uuid = uuid or str(uuid4()) @@ -341,7 +343,7 @@ def create(self, uuid: str, /, resource_type: typing.Optional[object] = None, de uuid, resource_type=resource_type, defaults=resource_dict ) _resource.save() - resourcebase_post_save(_resource.get_real_instance()) + resourcebase_post_save(_resource.get_real_instance(), *args, **kwargs) _resource.set_processing_state(enumerations.STATE_PROCESSED) except Exception as e: logger.exception(e) diff --git a/geonode/resource/metadata_storer.py b/geonode/resource/metadata_storer.py new file mode 100644 index 00000000000..d62f3837f4d --- /dev/null +++ b/geonode/resource/metadata_storer.py @@ -0,0 +1,15 @@ +import logging +from geonode.resource.manager import update_resource + +logger = logging.getLogger(__name__) + + +def store_metadata(instance, custom=None): + if not custom: + return instance + try: + return update_resource(instance, vals=custom) + except Exception as e: + logger.exception(e) + logger.error(f"Failed to update instance with custom payload: {custom}") + return instance diff --git a/geonode/settings.py b/geonode/settings.py index 71e45491684..69e69c54063 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -2226,7 +2226,8 @@ def get_geonode_catalogue_service(): List of modules that implement custom metadata storers that will be called when the metadata of a resource is saved """ METADATA_STORERS = [ - # 'geonode.resource.regions_storer.spatial_predicate_region_assignor', + # "geonode.resource.regions_storer.spatial_predicate_region_assignor", + # "geonode.resource.metadata_storer.store_metadata", ]