Skip to content

Commit

Permalink
[Fixes #12326] merge with master
Browse files Browse the repository at this point in the history
  • Loading branch information
mattiagiupponi committed Jul 11, 2024
2 parents 395022d + 007e640 commit 61f7205
Show file tree
Hide file tree
Showing 31 changed files with 1,619 additions and 23 deletions.
2 changes: 1 addition & 1 deletion geonode/assets/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def get_link_url(self, asset: LocalAsset):

class LocalAssetHandler(AssetHandlerInterface):

link_url_handlers = {"gpkg": IndexLocalLinkUrlHandler()}
link_url_handlers = {"3dtiles": IndexLocalLinkUrlHandler()}

@staticmethod
def handled_asset_class():
Expand Down
5 changes: 2 additions & 3 deletions geonode/assets/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

from rest_framework.response import Response
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.authentication import SessionAuthentication, BasicAuthentication

from geonode.assets.handlers import asset_handler_registry
Expand All @@ -39,7 +39,6 @@
DynamicSearchFilter,
)
from geonode.base.api.pagination import GeoNodeApiPagination
from geonode.base.api.permissions import UserHasPerms

logger = logging.getLogger(__name__)

Expand All @@ -50,7 +49,7 @@ class AssetViewSet(DynamicModelViewSet):
"""

authentication_classes = [SessionAuthentication, BasicAuthentication, OAuth2Authentication]
permission_classes = [IsAuthenticated, UserHasPerms]
permission_classes = [IsAuthenticatedOrReadOnly]
filter_backends = [
DynamicFilterBackend,
DynamicSortingFilter,
Expand Down
126 changes: 126 additions & 0 deletions geonode/base/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#
#########################################################################

import ast
import os
import re
import sys
Expand All @@ -40,9 +41,16 @@
from django.core.files.uploadedfile import SimpleUploadedFile
from django.contrib.auth import get_user_model

from owslib.etree import etree

from rest_framework.test import APITestCase
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser

from geonode.catalogue import get_catalogue
from geonode.catalogue.models import catalogue_post_save
from geonode.catalogue.views import csw_global_dispatch

from geonode.resource.manager import resource_manager
from guardian.shortcuts import get_anonymous_user

Expand Down Expand Up @@ -3328,3 +3336,121 @@ def test_geoapp_send_invalid_bbox_should_raise_error(self):
"code": "invalid_resource_exception",
}
self.assertDictEqual(expected, response.json())


pycsw_settings_all = settings.PYCSW.copy()

pycsw_settings_all["FILTER"] = {"resource_type__in": ["dataset", "resourcebase"]}


class TestBaseResourceBase(GeoNodeBaseTestSupport):

@classmethod
def setUpClass(cls) -> None:
super().setUpClass()
cls.user = get_user_model().objects.get(username="admin")

def test_simple_resourcebase_can_be_created_by_resourcemanager(self):
self.maxDiff = None
resource = resource_manager.create(
str(uuid4()), resource_type=ResourceBase, defaults={"title": "simple resourcebase", "owner": self.user}
)

self.assertIsNotNone(resource)
# minimum resource checks
self.assertEqual("resourcebase", resource.resource_type)
self.assertTrue(resource.link_set.all().exists())
self.assertEqual("simple resourcebase", resource.title)
self.assertTrue(self.user == resource.owner)
# check if the perms are set
anonymous_group = Group.objects.get(name="anonymous")
perms_expected = {
"users": {
self.user: set(
[
"delete_resourcebase",
"publish_resourcebase",
"change_resourcebase_permissions",
"view_resourcebase",
"change_resourcebase_metadata",
"change_resourcebase",
]
)
},
"groups": {anonymous_group: set(["view_resourcebase"])},
}

actual_perms = resource.get_all_level_info().copy()
self.assertIsNotNone(actual_perms)
self.assertTrue(self.user in actual_perms["users"].keys())
self.assertTrue(anonymous_group in actual_perms["groups"].keys())
self.assertSetEqual(perms_expected["users"][self.user], set(actual_perms["users"][self.user]))
self.assertSetEqual(perms_expected["groups"][anonymous_group], set(actual_perms["groups"][anonymous_group]))

# check if is returned from the API

self.assertTrue(self.client.login(username="admin", password="admin"))

response = self.client.get(reverse("base-resources-list"))

self.assertTrue(resource.pk in [int(x["pk"]) for x in response.json()["resources"]])

# checking csw call
catalogue_post_save(instance=resource, sender=resource.__class__)
# get all records
csw = get_catalogue()
record = csw.get_record(resource.uuid)
self.assertIsNotNone(record)
self.assertEqual(record.identification[0].title, resource.title)

def test_csw_should_not_return_resourcebase_by_default(self):
resource = resource_manager.create(
str(uuid4()), resource_type=ResourceBase, defaults={"title": "simple resourcebase", "owner": self.user}
)
dt = resource_manager.create(
str(uuid4()), resource_type=Dataset, defaults={"title": "simple dataset", "owner": self.user}
)

self.assertTrue(ResourceBase.objects.filter(pk=resource.pk).exists())
self.assertTrue(ResourceBase.objects.filter(pk=dt.pk).exists())

request = self.__csw_request_factory()

response = csw_global_dispatch(request)
root = etree.fromstring(response.content)
child = [x.attrib for x in root if "numberOfRecordsMatched" in x.attrib]
returned_results = ast.literal_eval(child[0].get("numberOfRecordsMatched", "0")) if child else 0
self.assertEqual(1, returned_results)

@override_settings(PYCSW=pycsw_settings_all)
def test_csw_should_return_resourcebase_if_defined_in_settings(self):
resource = resource_manager.create(
str(uuid4()), resource_type=ResourceBase, defaults={"title": "simple resourcebase", "owner": self.user}
)
dt = resource_manager.create(
str(uuid4()), resource_type=Dataset, defaults={"title": "simple dataset", "owner": self.user}
)

self.assertTrue(ResourceBase.objects.filter(pk=resource.pk).exists())
self.assertTrue(ResourceBase.objects.filter(pk=dt.pk).exists())

request = self.__csw_request_factory()

response = csw_global_dispatch(request)
root = etree.fromstring(response.content)
child = [x.attrib for x in root if "numberOfRecordsMatched" in x.attrib]
returned_results = ast.literal_eval(child[0].get("numberOfRecordsMatched", "0")) if child else 0
self.assertEqual(2, returned_results)

@staticmethod
def __csw_request_factory():
from django.contrib.auth.models import AnonymousUser

factory = RequestFactory()
url = "http://localhost:8000/catalogue/csw?request=GetRecords"
url += "&service=CSW&version=2.0.2&outputschema=http%3A%2F%2Fwww.isotc211.org%2F2005%2Fgmd"
url += "&elementsetname=brief&typenames=csw:Record&resultType=results"
request = factory.get(url)

request.user = AnonymousUser()
return request
46 changes: 46 additions & 0 deletions geonode/base/base_urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#########################################################################
#
# Copyright (C) 2020 OSGeo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################
from django.urls import re_path

from . import views

js_info_dict = {
"packages": ("geonode.base",),
}

urlpatterns = [
# 'geonode.resourcebases.views',
re_path(r"^(?P<resourcebaseid>\d+)/metadata$", views.resourcebase_metadata, name="resourcebase_metadata"),
re_path(
r"^(?P<resourcebaseid>[^/]*)/metadata_detail$",
views.resourcebase_metadata_detail,
name="resourcebase_metadata_detail",
),
re_path(
r"^(?P<resourcebaseid>\d+)/metadata_advanced$",
views.resourcebase_metadata_advanced,
name="resourcebase_metadata_advanced",
),
re_path(
r"^(?P<resourcebaseid>[^/]+)/embed$",
views.resourcebase_embed,
{"template": "base/base_embed.html"},
name="resourcebase_embed",
),
]
2 changes: 2 additions & 0 deletions geonode/base/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,8 @@ def clean_extra_metadata(self):
return json.dumps(validate_extra_metadata(cleaned_data, self.instance), indent=4)

class Meta:
model = ResourceBase

exclude = (
"contacts",
"name",
Expand Down
34 changes: 34 additions & 0 deletions geonode/base/management/command_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import logging
from django.conf import settings

DEFAULT_COMMAND_LOGGER_NAME = "geonode.commands"


def setup_logger(logger_name=DEFAULT_COMMAND_LOGGER_NAME, formatter_name="command", handler_name="command"):
if logger_name not in settings.LOGGING["loggers"]:
format = "%(levelname)-7s %(asctime)s %(message)s"

settings.LOGGING["formatters"][formatter_name] = {
"format": format
}
settings.LOGGING["handlers"][handler_name] = {
"level": "DEBUG",
"class": "logging.StreamHandler",
"formatter": formatter_name
}
settings.LOGGING["loggers"][logger_name] = {
"handlers": [handler_name],
"level": "INFO",
"propagate": False
}

handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(fmt=format))
handler.setLevel(logging.DEBUG)

logger = logging.getLogger(logger_name)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
logger.propagate = False

return logger
15 changes: 13 additions & 2 deletions geonode/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from django.utils.translation import gettext_lazy as _
from django.contrib.contenttypes.models import ContentType
from django.utils.html import strip_tags
from django.urls import reverse
from mptt.models import MPTTModel, TreeForeignKey

from PIL import Image, ImageOps
Expand Down Expand Up @@ -1330,8 +1331,14 @@ def keyword_csv(self):
return ""

def get_absolute_url(self):
from geonode.client.hooks import hookset

try:
return self.get_real_instance().get_absolute_url() if self != self.get_real_instance() else None
return (
self.get_real_instance().get_absolute_url()
if self != self.get_real_instance()
else hookset.get_absolute_url(self)
)
except Exception as e:
logger.exception(e)
return None
Expand Down Expand Up @@ -1452,7 +1459,11 @@ def download_links(self):

@property
def embed_url(self):
return self.get_real_instance().embed_url if self != self.get_real_instance() else None
return (
self.get_real_instance().embed_url
if self != self.get_real_instance()
else reverse("resourcebase_embed", kwargs={"resourcebaseid": self.pk})
)

def get_tiles_url(self):
"""Return URL for Z/Y/X mapping clients or None if it does not exist."""
Expand Down
14 changes: 14 additions & 0 deletions geonode/base/templates/base/base_embed.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% load i18n %}
{% load base_tags %}
{% load client_lib_tags %}

{% block head %}

<style>
#paneltbar {
margin-top: 90px !important;
}
</style>

{% get_resourcebase_embed %}
{% endblock %}
Loading

0 comments on commit 61f7205

Please sign in to comment.