Skip to content

Commit c73eff1

Browse files
[Fixes #14035] Implementation of a common ResourceManager base class for all resource types (#14053)
* [Fixes #14035] Implementation of a common ResourceManager base class for all resource types * [Fixes #14035] Add lazy wrapper for custom resource managers --------- Co-authored-by: Mattia Giupponi <mattia.giupponi@gmail.com>
1 parent 139b86e commit c73eff1

54 files changed

Lines changed: 791 additions & 287 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

geonode/assets/tests.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ def test_download_with_attachment_for_anonymous(self):
381381
any user without download permissions
382382
cannot download the asset
383383
"""
384-
from geonode.resource.manager import resource_manager
384+
from geonode.resource.registry import resource_manager_registry, dataset_manager
385385
from geonode.layers.models import Dataset
386386
from guardian.shortcuts import get_anonymous_user
387387

@@ -393,7 +393,7 @@ def test_download_with_attachment_for_anonymous(self):
393393
resource = None
394394
try:
395395
# creating resoruce
396-
resource = resource_manager.create(
396+
resource = dataset_manager.create(
397397
None, resource_type=Dataset, defaults={"owner": bobby, "asset": asset}
398398
)
399399
# getting perms
@@ -403,7 +403,9 @@ def test_download_with_attachment_for_anonymous(self):
403403
# and anonymous just to be sure
404404
resource_perms["groups"][get_anonymous_user().groups.first()] = ["view_resourcebase"]
405405
# resetting the permissions for the resource
406-
resource_manager.set_permissions(resource.uuid, instance=resource, permissions=resource_perms)
406+
resource_manager_registry.get_for_instance(resource).set_permissions(
407+
resource.uuid, instance=resource, permissions=resource_perms
408+
)
407409
url = reverse("assets-download", kwargs={"pk": asset.pk})
408410
response = self.client.get(url)
409411
self.assertEqual(response.status_code, 403)

geonode/base/admin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,9 @@ def delete_queryset(self, request, queryset):
390390
through the admin batch action
391391
"""
392392
for obj in queryset:
393-
from geonode.resource.manager import resource_manager
393+
from geonode.resource.registry import resource_manager_registry
394394

395-
resource_manager.delete(obj.uuid, instance=obj)
395+
resource_manager_registry.get_for_instance(obj).delete(obj.uuid, instance=obj)
396396

397397
class Meta:
398398
pass

geonode/base/api/tests.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
from geonode.catalogue.models import catalogue_post_save
5353
from geonode.catalogue.views import csw_global_dispatch
5454

55-
from geonode.resource.manager import resource_manager
55+
from geonode.resource.registry import resource_manager_registry, dataset_manager
5656
from guardian.shortcuts import get_anonymous_user
5757

5858
from geonode.assets.utils import create_asset_and_link
@@ -2108,7 +2108,7 @@ def test_set_thumbnail_from_bbox_from_Anonymous_user_raise_permission_error(self
21082108
self.assertEqual(response.status_code, 401)
21092109
self.assertEqual(expected, response.json())
21102110

2111-
@patch("geonode.base.api.views.resource_manager.set_thumbnail")
2111+
@patch("geonode.layers.manager.DatasetResourceManager.set_thumbnail")
21122112
def test_set_thumbnail_from_bbox_from_logged_user_for_existing_dataset(self, mock_set_thumbnail):
21132113
"""
21142114
Given a logged User and an existing dataset, should successfully trigger thumbnail generation.
@@ -2167,7 +2167,7 @@ def test_set_thumbnail_from_bbox_from_logged_user_for_existing_doc(self):
21672167
self.assertEqual(response.status_code, 405)
21682168
self.assertEqual(expected, response.json())
21692169

2170-
@patch("geonode.base.api.views.resource_manager.set_thumbnail", return_value=False)
2170+
@patch("geonode.layers.manager.DatasetResourceManager.set_thumbnail", return_value=False)
21712171
def test_set_thumbnail_from_bbox_from_logged_user_for_existing_dataset_raise_exp(self, mock_set_thumbnail):
21722172
"""
21732173
Given a logged User and an existing dataset, should raise a ThumbnailException.
@@ -2602,7 +2602,7 @@ def test_resource_service_permissions_with_partial_restriction(self):
26022602
def test_resource_service_copy(self):
26032603
files = os.path.join(gisdata.GOOD_DATA, "vector/single_point.shp")
26042604
files_as_dict, _ = get_files(files)
2605-
resource = resource_manager.create(
2605+
resource = dataset_manager.create(
26062606
str(uuid4()),
26072607
Dataset,
26082608
defaults={
@@ -2701,7 +2701,7 @@ def test_resource_service_copy_with_perms_dataset_set_default_perms(self):
27012701
with self.settings(ASYNC_SIGNALS=False):
27022702
files = os.path.join(gisdata.GOOD_DATA, "vector/single_point.shp")
27032703
files_as_dict, _ = get_files(files)
2704-
resource = resource_manager.create(
2704+
resource = dataset_manager.create(
27052705
None,
27062706
resource_type=Dataset,
27072707
defaults={
@@ -3140,10 +3140,12 @@ def test_delete_will_delete_single_metadata(self):
31403140
self.assertEqual([], response.json())
31413141

31423142
def test_user_without_view_perms_cannot_see_the_endpoint(self):
3143-
from geonode.resource.manager import resource_manager
3143+
from geonode.resource.registry import resource_manager_registry
31443144

31453145
self.client.login(username="bobby", password="bob")
3146-
resource_manager.remove_permissions(self.layer.uuid, instance=self.layer.get_self_resource())
3146+
resource_manager_registry.get_for_instance(self.layer.get_self_resource()).remove_permissions(
3147+
self.layer.uuid, instance=self.layer.get_self_resource()
3148+
)
31473149
url = reverse("base-resources-extra-metadata", args=[self.layer.id])
31483150
response = self.client.get(url, content_type="application/json")
31493151
self.assertTrue(401, response.status_code)
@@ -3753,7 +3755,7 @@ def setUpClass(cls) -> None:
37533755

37543756
def test_simple_resourcebase_can_be_created_by_resourcemanager(self):
37553757
self.maxDiff = None
3756-
resource = resource_manager.create(
3758+
resource = resource_manager_registry.get_for_model(ResourceBase).create(
37573759
str(uuid4()), resource_type=ResourceBase, defaults={"title": "simple resourcebase", "owner": self.user}
37583760
)
37593761

@@ -3807,19 +3809,21 @@ def test_simple_resourcebase_can_be_created_by_resourcemanager(self):
38073809
self.assertEqual(record.identification[0].title, resource.title)
38083810

38093811
def test_resource_index_created(self):
3810-
resource = resource_manager.create(
3812+
resource = resource_manager_registry.get_for_model(ResourceBase).create(
38113813
str(uuid4()), resource_type=ResourceBase, defaults={"title": "simple resourcebase", "owner": self.user}
38123814
)
38133815

3814-
resource = resource_manager.update(resource.uuid, instance=resource, vals={})
3816+
resource = resource_manager_registry.get_for_instance(resource).update(
3817+
resource.uuid, instance=resource, vals={}
3818+
)
38153819

38163820
self.assertTrue(ResourceIndex.objects.filter(resource=resource).exists())
38173821

38183822
def test_csw_should_not_return_resourcebase_by_default(self):
3819-
resource = resource_manager.create(
3823+
resource = resource_manager_registry.get_for_model(ResourceBase).create(
38203824
str(uuid4()), resource_type=ResourceBase, defaults={"title": "simple resourcebase", "owner": self.user}
38213825
)
3822-
dt = resource_manager.create(
3826+
dt = dataset_manager.create(
38233827
str(uuid4()), resource_type=Dataset, defaults={"title": "simple dataset", "owner": self.user}
38243828
)
38253829

@@ -3836,10 +3840,10 @@ def test_csw_should_not_return_resourcebase_by_default(self):
38363840

38373841
@override_settings(PYCSW=pycsw_settings_all)
38383842
def test_csw_should_return_resourcebase_if_defined_in_settings(self):
3839-
resource = resource_manager.create(
3843+
resource = resource_manager_registry.get_for_model(ResourceBase).create(
38403844
str(uuid4()), resource_type=ResourceBase, defaults={"title": "simple resourcebase", "owner": self.user}
38413845
)
3842-
dt = resource_manager.create(
3846+
dt = dataset_manager.create(
38433847
str(uuid4()), resource_type=Dataset, defaults={"title": "simple dataset", "owner": self.user}
38443848
)
38453849

geonode/base/api/views.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
from geonode.security.registry import permissions_registry
8888
from geonode.resource.models import ExecutionRequest
8989
from geonode.resource.api.tasks import resouce_service_dispatcher
90-
from geonode.resource.manager import resource_manager
90+
from geonode.resource.registry import resource_manager_registry
9191

9292
from .permissions import (
9393
IsOwnerOrAdmin,
@@ -711,7 +711,7 @@ def set_thumbnail_from_bbox(self, request, resource_id, *args, **kwargs):
711711
bbox = request_body["bbox"] + [request_body["srid"]]
712712
zoom = request_body.get("zoom", None)
713713

714-
success = resource_manager.set_thumbnail(
714+
success = resource_manager_registry.get_for_instance(resource).set_thumbnail(
715715
resource.uuid,
716716
instance=resource,
717717
bbox=bbox,
@@ -1278,7 +1278,9 @@ def set_thumbnail(self, request, pk, *args, **kwargs):
12781278
except Exception:
12791279
raise ValidationError(detail="Invalid data provided")
12801280
if thumbnail:
1281-
resource_manager.set_thumbnail(resource.uuid, instance=resource, thumbnail=thumbnail)
1281+
resource_manager_registry.get_for_instance(resource).set_thumbnail(
1282+
resource.uuid, instance=resource, thumbnail=thumbnail
1283+
)
12821284
return Response({"thumbnail_url": resource.thumbnail_url})
12831285
return Response("Unable to set thumbnail", status=status.HTTP_400_BAD_REQUEST)
12841286

geonode/base/models.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,9 +1085,11 @@ def delete(self, notify=True, *args, **kwargs):
10851085
"""
10861086
Send a notification when a layer, map or document is deleted
10871087
"""
1088-
from geonode.resource.manager import resource_manager
1088+
from geonode.resource.registry import resource_manager_registry
10891089

1090-
resource_manager.remove_permissions(self.uuid, instance=self.get_real_instance())
1090+
resource_manager_registry.get_for_instance(self).remove_permissions(
1091+
self.uuid, instance=self.get_real_instance()
1092+
)
10911093

10921094
# delete assets. TODO: when standalone Assets will be allowed, only dependable Assets shall be removed
10931095
links_with_assets = Link.objects.filter(resource=self, asset__isnull=False).prefetch_related("asset")

geonode/base/tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
from geonode.base.templatetags.user_messages import show_notification
8383
from geonode import geoserver
8484
from geonode.decorators import on_ogc_backend
85-
from geonode.resource.manager import resource_manager
85+
from geonode.resource.registry import dataset_manager
8686
from geonode.base.api.serializers import ResourceBaseSerializer
8787

8888
test_image = Image.new("RGBA", size=(50, 50), color=(155, 0, 0))
@@ -1205,7 +1205,7 @@ def test_region_assignment_for_extent(self):
12051205

12061206
@override_settings(METADATA_STORERS=["geonode.resource.regions_storer.spatial_predicate_region_assignor"])
12071207
def test_regions_are_assigned_if_handler_is_used(self):
1208-
dataset = resource_manager.create(
1208+
dataset = dataset_manager.create(
12091209
None,
12101210
resource_type=Dataset,
12111211
defaults=dict(owner=get_user_model().objects.first(), title="test_region_dataset", is_approved=True),

geonode/base/views.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
from geonode.utils import resolve_object
4444
from geonode.groups.models import GroupProfile
4545
from geonode.tasks.tasks import set_permissions
46-
from geonode.resource.manager import resource_manager
46+
from geonode.resource.registry import resource_manager_registry
4747
from geonode.security.utils import get_visible_resources
4848
from geonode.notifications_helper import send_notification
4949
from geonode.base.utils import OwnerRightsRequestViewUtils, remove_country_from_languagecode
@@ -374,13 +374,14 @@ def resourcebase_embed(request, resourcebaseid, template="base/base_edit.html"):
374374

375375
r = resourcebase_obj
376376
if request.method in ("POST", "PATCH", "PUT"):
377-
r = resource_manager.update(resourcebase_obj.uuid, instance=resourcebase_obj, notify=True)
377+
resolved_resource_manager = resource_manager_registry.get_for_instance(resourcebase_obj)
378+
r = resolved_resource_manager.update(resourcebase_obj.uuid, instance=resourcebase_obj, notify=True)
378379

379-
resource_manager.set_permissions(
380+
resolved_resource_manager.set_permissions(
380381
resourcebase_obj.uuid, instance=resourcebase_obj, permissions=ast.literal_eval(permissions_json)
381382
)
382383

383-
resource_manager.set_thumbnail(resourcebase_obj.uuid, instance=resourcebase_obj, overwrite=False)
384+
resolved_resource_manager.set_thumbnail(resourcebase_obj.uuid, instance=resourcebase_obj, overwrite=False)
384385

385386
access_token = None
386387
if request and request.user:

geonode/documents/admin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ def delete_queryset(self, request, queryset):
7777
through the admin batch action
7878
"""
7979
for obj in queryset:
80-
from geonode.resource.manager import resource_manager
80+
from geonode.resource.registry import resource_manager_registry
8181

82-
resource_manager.delete(obj.uuid, instance=obj)
82+
resource_manager_registry.get_for_instance(obj).delete(obj.uuid, instance=obj)
8383

8484

8585
admin.site.register(Document, DocumentAdmin)

geonode/documents/api/views.py

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919

2020
from drf_spectacular.utils import extend_schema
2121
from pathlib import Path
22+
from uuid import uuid4
2223
from dynamic_rest.viewsets import DynamicModelViewSet
2324
from dynamic_rest.filters import DynamicFilterBackend, DynamicSortingFilter
2425

2526
from rest_framework.decorators import action
2627
from rest_framework.permissions import IsAuthenticatedOrReadOnly
2728
from geonode import settings
2829

29-
from geonode.assets.utils import create_asset_and_link
3030
from geonode.base.api.filters import DynamicSearchFilter, ExtentFilter, AdvertisedFilter
3131
from geonode.base.api.pagination import GeoNodeApiPagination
3232
from geonode.base.api.permissions import UserHasPerms
@@ -36,10 +36,7 @@
3636
from geonode.documents.api.exceptions import DocumentException
3737
from geonode.documents.models import Document
3838
from geonode.metadata.multilang.views import MultiLangViewMixin
39-
from geonode.metadata.manager import metadata_manager
40-
from geonode.resource.utils import resourcebase_post_save, infer_default_metadata
41-
from geonode.storage.manager import StorageManager
42-
from geonode.resource.manager import resource_manager
39+
from geonode.resource.registry import document_manager
4340

4441
from .serializers import DocumentSerializer
4542
from .permissions import DocumentPermissionsFilter
@@ -94,7 +91,6 @@ def perform_create(self, serializer):
9491
--form 'doc_file=@"/C:/Users/user/Pictures/BcMc-a6T9IM.jpg"' \
9592
--form 'metadata_only="False"'
9693
"""
97-
manager = None
9894
serializer.is_valid(raise_exception=True)
9995
file = serializer.validated_data.pop("file_path", None) or serializer.validated_data.pop("doc_file", None)
10096
doc_url = serializer.validated_data.pop("doc_url", None)
@@ -106,51 +102,35 @@ def perform_create(self, serializer):
106102
if file and doc_url:
107103
raise DocumentException(detail="Either a file or a URL must be specified, not both")
108104

109-
if not extension:
105+
if not extension and file:
110106
filename = file if isinstance(file, str) else file.name
111107
extension = Path(filename).suffix.replace(".", "")
112108

113109
if extension not in settings.ALLOWED_DOCUMENT_TYPES:
114110
raise DocumentException("The file provided is not in the supported extensions list")
115111

116112
try:
117-
resolved_owner = resource_manager.resolve_creation_owner(self.request.user)
113+
request_user = self.request.user
118114
payload = {
119-
"owner": resolved_owner,
115+
**serializer.validated_data,
116+
"owner": request_user,
120117
"extension": extension,
121118
"resource_type": "document",
122119
}
123120
if doc_url:
124121
payload["doc_url"] = doc_url
125122
payload["sourcetype"] = enumerations.SOURCE_TYPE_REMOTE
126123

127-
resource = serializer.save(**payload)
128-
129-
if file:
130-
manager = StorageManager(remote_files={"base_file": file})
131-
manager.clone_remote_files()
132-
create_asset_and_link(
133-
resource, self.request.user, [manager.get_retrieved_paths().get("base_file")], clone_files=True
134-
)
135-
manager.delete_retrieved_paths(force=True)
136-
137-
resource.set_missing_info()
138-
metadata_manager.update_schema_instance_partial(
139-
resource,
140-
infer_default_metadata(resource.get_real_instance()),
141-
user=self.request.user,
124+
instance = document_manager.create(
125+
str(uuid4()),
126+
resource_type=Document,
127+
defaults=payload,
128+
file=file,
129+
user=request_user,
142130
)
143-
resourcebase_post_save(resource.get_real_instance())
144-
resource_manager.finalize_creation_permissions(
145-
resource, owner=resolved_owner, initial_user=self.request.user
146-
)
147-
resource.handle_moderated_uploads()
148-
resource_manager.set_thumbnail(resource.uuid, instance=resource, overwrite=False)
149-
return resource
131+
serializer.instance = instance
150132
except Exception as e:
151133
logger.error(f"Error creating document {serializer.validated_data}", exc_info=e)
152-
if manager:
153-
manager.delete_retrieved_paths()
154134
raise e
155135

156136
@extend_schema(

0 commit comments

Comments
 (0)