Skip to content

Commit

Permalink
[Fixes #12456] Implement the ResourceHandler concept
Browse files Browse the repository at this point in the history
  • Loading branch information
mattiagiupponi committed Jul 31, 2024
1 parent 2e4dae2 commit b57f222
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 40 deletions.
43 changes: 3 additions & 40 deletions geonode/base/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
from django.forms.models import model_to_dict
from django.contrib.auth import get_user_model
from django.db.models.query import QuerySet
from geonode.assets.utils import get_default_asset
from geonode.people import Roles
from django.http import QueryDict
from deprecated import deprecated
Expand Down Expand Up @@ -63,10 +62,9 @@
from geonode.geoapps.models import GeoApp
from geonode.groups.models import GroupCategory, GroupProfile
from geonode.base.api.fields import ComplexDynamicRelationField
from geonode.layers.utils import get_download_handlers, get_default_dataset_download_handler
from geonode.assets.handlers import asset_handler_registry
from geonode.resource.manager import resource_manager
from geonode.utils import build_absolute_uri
from geonode.security.utils import get_resources_with_perms, get_geoapp_subtypes
from geonode.security.utils import get_resources_with_perms
from geonode.resource.models import ExecutionRequest
from django.contrib.gis.geos import Polygon

Expand Down Expand Up @@ -301,42 +299,7 @@ def get_attribute(self, instance):
logger.exception(e)
raise e

asset = get_default_asset(_instance)
if asset is not None:
asset_url = asset_handler_registry.get_handler(asset).create_download_url(asset)

if _instance.resource_type in ["map"] + get_geoapp_subtypes():
return []
elif _instance.resource_type in ["document"]:
payload = [
{
"url": _instance.download_url,
"ajax_safe": _instance.download_is_ajax_safe,
},
]
if asset:
payload.append({"url": asset_url, "ajax_safe": False, "default": False})
return payload

elif _instance.resource_type in ["dataset"]:
download_urls = []
# lets get only the default one first to set it
default_handler = get_default_dataset_download_handler()
obj = default_handler(self.context.get("request"), _instance.alternate)
if obj.download_url:
download_urls.append({"url": obj.download_url, "ajax_safe": obj.is_ajax_safe, "default": True})
# then let's prepare the payload with everything
for handler in get_download_handlers():
obj = handler(self.context.get("request"), _instance.alternate)
if obj.download_url:
download_urls.append({"url": obj.download_url, "ajax_safe": obj.is_ajax_safe, "default": False})

if asset:
download_urls.append({"url": asset_url, "ajax_safe": True, "default": False if download_urls else True})

return download_urls
else:
return []
return resource_manager.get_manager(_instance).download_urls(**self.context)


class FavoriteField(DynamicComputedField):
Expand Down
24 changes: 24 additions & 0 deletions geonode/documents/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from geonode.documents.models import Document
from geonode.resource.handler import BaseResourceHandler
import logging

logger = logging.getLogger()


class DocumentHandler(BaseResourceHandler):

@staticmethod
def can_handle(instance):
return isinstance(instance, Document)

def download_urls(self):
"""
Specific method that return the download URL of the document
"""
super().download_urls()
return [
{
"url": self.instance.download_url,
"ajax_safe": self.instance.download_is_ajax_safe,
},
]
15 changes: 15 additions & 0 deletions geonode/geoapps/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from geonode.geoapps.models import GeoApp
from geonode.resource.handler import BaseResourceHandler
import logging

logger = logging.getLogger()


class GeoAppHandler(BaseResourceHandler):
@staticmethod
def can_handle(instance):
return isinstance(instance, GeoApp)

def download_urls(self):
logger.debug("Download is not available for maps")
return []
49 changes: 49 additions & 0 deletions geonode/layers/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from geonode.assets.utils import get_default_asset
from geonode.base.models import ResourceBase
from geonode.layers.models import Dataset
from geonode.resource.handler import BaseResourceHandler
import logging
from geonode.assets.handlers import asset_handler_registry
from geonode.layers.utils import get_download_handlers, get_default_dataset_download_handler

logger = logging.getLogger()


class Tiles3DHandler(BaseResourceHandler):
@staticmethod
def can_handle(instance):
return isinstance(instance, ResourceBase) and instance.subtype == "3dtiles"

def download_urls(self, **kwargs):
"""
Specific method that return the download URL of the document
"""
super().download_urls()
asset = get_default_asset(self.instance)
if asset is not None:
asset_url = asset_handler_registry.get_handler(asset).create_download_url(asset)
return asset_url


class DatasetHandler(BaseResourceHandler):
@staticmethod
def can_handle(instance):
return isinstance(instance, Dataset)

def download_urls(self, **kwargs):
super().download_urls()
"""
Specific method that return the download URL of the document
"""
download_urls = []
# lets get only the default one first to set it
default_handler = get_default_dataset_download_handler()
obj = default_handler(kwargs.get("request"), self.instance.alternate)
if obj.download_url:
download_urls.append({"url": obj.download_url, "ajax_safe": obj.is_ajax_safe, "default": True})
# then let's prepare the payload with everything
for handler in get_download_handlers():
obj = handler(kwargs.get("request"), self.instance.alternate)
if obj.download_url:
download_urls.append({"url": obj.download_url, "ajax_safe": obj.is_ajax_safe, "default": False})
return download_urls
15 changes: 15 additions & 0 deletions geonode/maps/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from geonode.maps.models import Map
from geonode.resource.handler import BaseResourceHandler
import logging

logger = logging.getLogger()


class MapHandler(BaseResourceHandler):
@staticmethod
def can_handle(instance):
return isinstance(instance, Map)

def download_urls(self, **kwargs):
logger.debug("Download is not available for maps")
return []
5 changes: 5 additions & 0 deletions geonode/resource/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#########################################################################
from django.apps import AppConfig
from django.urls import include, re_path
from django.conf import settings
from django.utils.module_loading import import_string


class GeoNodeResourceConfig(AppConfig):
Expand All @@ -28,3 +30,6 @@ def ready(self):
from geonode.urls import urlpatterns

urlpatterns += [re_path(r"^api/v2/", include("geonode.resource.api.urls"))]

for el in settings.RESOURCE_HANDLERS:
import_string(el).register()
63 changes: 63 additions & 0 deletions geonode/resource/handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from abc import ABC
import logging

logger = logging.getLogger(__file__)


class BaseResourceHandler(ABC):
"""
Base abstract resource handler object
define the required method needed to define a resource handler
As first implementation it will take care of the download url
and the download response for a resource
"""

REGISTRY = []

def __init__(self) -> None:
self.resource = None

def __str__(self):
return f"{self.__module__}.{self.__class__.__name__}"

def __repr__(self):
return self.__str__()

@classmethod
def init_class(cls, instance):
cls.instance = instance

@classmethod
def register(cls):
BaseResourceHandler.REGISTRY.append(cls)

@classmethod
def get_registry(cls):
return BaseResourceHandler.REGISTRY

def get_handler_by_instance(self, instance):
"""
Given a resource, should return it's handler
"""
for handler in self.get_registry():
if handler.can_handle(instance):
self.init_class(instance)
return handler()
logger.error("No handlers found for the given resource")
return None

def download_urls(self, **kwargs):
"""
return the download url for each resource
"""
if not self.instance:
logger.warning("No instance declared, so is not possible to return the download url")
return None

def download_response(self, **kwargs):
"""
Return the download response for the resource
"""


resource_hander = BaseResourceHandler()
5 changes: 5 additions & 0 deletions geonode/resource/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -976,5 +976,10 @@ def set_thumbnail(
logger.exception(e)
return False

def get_manager(self, instance):
from geonode.resource.handler import resource_hander

return resource_hander.get_handler_by_instance(instance=instance)


resource_manager = ResourceManager()
9 changes: 9 additions & 0 deletions geonode/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2379,3 +2379,12 @@ def get_geonode_catalogue_service():
]
INSTALLED_APPS += ("geonode.assets",)
GEONODE_APPS += ("geonode.assets",)


RESOURCE_HANDLERS = [
"geonode.layers.handlers.Tiles3DHandler",
"geonode.layers.handlers.DatasetHandler",
"geonode.maps.handlers.MapHandler",
"geonode.documents.handlers.DocumentHandler",
"geonode.geoapps.handlers.GeoAppHandler",
]

0 comments on commit b57f222

Please sign in to comment.