Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions geonode/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from django.urls import reverse
from django.contrib.auth.models import Group
from django.contrib.auth import get_user_model
from django.test import SimpleTestCase
from django.test.utils import override_settings

from guardian.shortcuts import get_anonymous_user
Expand Down Expand Up @@ -1387,3 +1388,46 @@ def test_delete_asset_no_permission(self):
response = self.client.delete(url)
self.assertEqual(response.status_code, 403)
self.assertTrue(Asset.objects.filter(pk=self.asset1.pk).exists())


class RouterUrlpatternsCompletenessTest(SimpleTestCase):
"""Guards the shared /api/v2/ router against app-loading-order regressions."""

def test_router_is_complete(self):
from geonode.api.urls import router

names = {getattr(pattern, "name", None) for pattern in router.urls}

# first 5 were previously only reachable via a ready() hook or a stale router.urls read;
# base-resources-list is a baseline that was never affected
for expected in (
"executionrequest-list",
"upload-size-limits-list",
"upload-parallelism-limits-list",
"assets-list",
"metadata-list",
"base-resources-list",
):
with self.subTest(name=expected):
self.assertIn(expected, names)

def test_resource_and_harvesting_no_longer_inject_urls_from_ready(self):
import inspect

import geonode.harvesting.apps
import geonode.resource.apps

for module in (geonode.resource.apps, geonode.harvesting.apps):
with self.subTest(module=module.__name__):
source = inspect.getsource(module)
self.assertNotIn("geonode.urls", source)
self.assertNotIn("urlpatterns", source)

def test_upload_no_longer_has_the_dead_override_mechanism(self):
import inspect

import geonode.upload.apps

source = inspect.getsource(geonode.upload.apps)
self.assertNotIn("run_setup_hooks", source)
self.assertNotIn("url_already_injected", source)
5 changes: 3 additions & 2 deletions geonode/facets/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
from django.urls import path
from .views import ListFacetsView, GetFacetView

# "facets" prefix comes from the include() in geonode/urls.py.
urlpatterns = [
path("facets", ListFacetsView.as_view(), name="list_facets"),
path("facets/<facet>", GetFacetView.as_view(), name="get_facet"),
path("", ListFacetsView.as_view(), name="list_facets"),
path("/<facet>", GetFacetView.as_view(), name="get_facet"),
]
3 changes: 0 additions & 3 deletions geonode/harvesting/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

from django.apps import AppConfig
from django.conf import settings
from django.urls import include, re_path

from . import config

Expand All @@ -28,10 +27,8 @@ class HarvestingAppConfig(AppConfig):
name = "geonode.harvesting"

def ready(self):
from geonode.urls import urlpatterns
from . import signals # noqa

urlpatterns += [re_path(r"^api/v2/", include("geonode.harvesting.api.urls"))]
settings.CELERY_BEAT_SCHEDULE["harvesting-scheduler"] = {
"task": "geonode.harvesting.tasks.harvesting_scheduler",
"schedule": config.get_setting("HARVESTER_SCHEDULER_FREQUENCY_MINUTES") * 0.5,
Expand Down
9 changes: 5 additions & 4 deletions geonode/management_commands_http/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
from geonode.management_commands_http.routers import router


# "management/" prefix comes from the include() in geonode/urls.py.
urlpatterns = [
re_path(r"management/commands/$", ManagementCommandView.as_view()),
re_path(r"management/commands/(?P<cmd_name>\w+)/$", ManagementCommandView.as_view()),
re_path(r"management/commands/(?P<cmd_name>\w+)/", include(router.urls)),
path("management/", include(router.urls)),
re_path(r"commands/$", ManagementCommandView.as_view()),
re_path(r"commands/(?P<cmd_name>\w+)/$", ManagementCommandView.as_view()),
re_path(r"commands/(?P<cmd_name>\w+)/", include(router.urls)),
path("", include(router.urls)),
]
21 changes: 11 additions & 10 deletions geonode/metadata/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,42 +31,43 @@

router.register(r"metadata", views.MetadataViewSet, "metadata")

urlpatterns = router.urls + [
# metadata-* routes come from router.urls in geonode/urls.py; only extra paths here.
urlpatterns = [
path(
r"metadata/autocomplete/thesaurus/<thesaurusid>/keywords",
r"autocomplete/thesaurus/<thesaurusid>/keywords",
views.tkeywords_autocomplete,
name="metadata_autocomplete_tkeywords",
),
path(r"metadata/autocomplete/users", ProfileAutocomplete.as_view(), name="metadata_autocomplete_users"),
path(r"autocomplete/users", ProfileAutocomplete.as_view(), name="metadata_autocomplete_users"),
path(
r"metadata/autocomplete/resources",
r"autocomplete/resources",
MetadataLinkedResourcesAutocomplete.as_view(),
name="metadata_autocomplete_resources",
),
path(
r"metadata/autocomplete/regions",
r"autocomplete/regions",
MetadataRegionsAutocomplete.as_view(),
name="metadata_autocomplete_regions",
),
path(
r"metadata/autocomplete/hkeywords",
r"autocomplete/hkeywords",
MetadataHKeywordAutocomplete.as_view(),
name="metadata_autocomplete_hkeywords",
),
path(
r"metadata/autocomplete/groups",
r"autocomplete/groups",
MetadataGroupAutocomplete.as_view(),
name="metadata_autocomplete_groups",
),
path(
r"metadata/autocomplete/categories",
r"autocomplete/categories",
views.categories_autocomplete,
name="metadata_autocomplete_categories",
),
path(
r"metadata/autocomplete/licenses",
r"autocomplete/licenses",
views.licenses_autocomplete,
name="metadata_autocomplete_licenses",
),
# path(r"metadata/autocomplete/users", login_required(ProfileAutocomplete.as_view()), name="metadata_autocomplete_users"),
# path(r"autocomplete/users", login_required(ProfileAutocomplete.as_view()), name="metadata_autocomplete_users"),
]
6 changes: 1 addition & 5 deletions geonode/resource/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,17 @@
#
#########################################################################
from django.apps import AppConfig
from django.urls import include, re_path


class GeoNodeResourceConfig(AppConfig):
name = "geonode.resource"
verbose_name = "GeoNode Resource Service and Manager"

def ready(self):
from geonode.urls import urlpatterns

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


def run_setup_hooks(*args, **kwargs):
from geonode.resource.registry import resource_manager_registry

resource_manager_registry.init_registry()
resource_manager_registry.init_registry()
20 changes: 0 additions & 20 deletions geonode/upload/api/urls.py

This file was deleted.

24 changes: 0 additions & 24 deletions geonode/upload/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,10 @@ class UploadAppConfig(AppConfig):
def ready(self):
"""Finalize setup"""
init_feature_validators_registry()
run_setup_hooks()
super(UploadAppConfig, self).ready()


def init_feature_validators_registry():
from geonode.upload.registry import feature_validators_registry

feature_validators_registry.init_registry()


def run_setup_hooks(*args, **kwargs):
"""
Run basic setup configuration for the importer app.
Here we are overriding the upload API url
"""
from geonode.urls import urlpatterns
from django.urls import re_path, include

url_already_injected = any(
[
"geonode.upload.urls" in x.urlconf_name.__name__
for x in urlpatterns
if hasattr(x, "urlconf_name") and not isinstance(x.urlconf_name, list)
]
)

if not url_already_injected:
urlpatterns.insert(
0,
re_path(r"^api/v2/", include("geonode.upload.api.urls")),
)
25 changes: 12 additions & 13 deletions geonode/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,6 @@
re_path(r"^sitemap\.xml$", sitemap, {"sitemaps": sitemaps}, name="sitemap"),
re_path(r"^robots\.txt$", TemplateView.as_view(template_name="robots.txt"), name="robots"),
re_path(r"(.*version\.txt)$", version.version, name="version"),
]

urlpatterns += [
# ResourceBase views
re_path(r"^base/", include("geonode.base.urls")),
re_path(r"^resources/", include("geonode.base.base_urls")),
Expand Down Expand Up @@ -95,7 +92,6 @@
re_path(r"^account/", include("allauth.urls")),
re_path(r"^invitations/", include("geonode.invitations.urls", namespace="geonode.invitations")),
re_path(r"^people/", include("geonode.people.urls")),
re_path(r"^api/v2/users/", include("geonode.people.api.urls")),
re_path(r"^avatar/", include("avatar.urls")),
re_path(r"^activity/", include("actstream.urls")),
re_path(r"^announcements/", include("announcements.urls")),
Expand Down Expand Up @@ -126,14 +122,16 @@
ResourceImporter.as_view({"put": "copy"}),
name="importer_resource_copy",
),
re_path(r"^api/v2/", include(router.urls)),
# API v2 (resource, harvesting used to self-register from AppConfig.ready(); hardcoded now, like every other app)
re_path(r"^api/v2/users/", include("geonode.people.api.urls")),
re_path(r"^api/v2/", include("geonode.resource.api.urls")),
re_path(r"^api/v2/", include("geonode.harvesting.api.urls")),
re_path(r"^api/v2/", include("geonode.api.urls")),
re_path(r"^api/v2/", include("geonode.management_commands_http.urls")),
re_path(r"^api/v2/management/", include("geonode.management_commands_http.urls")),
re_path(r"^api/v2/api-auth/", include("rest_framework.urls", namespace="geonode_rest_framework")),
re_path(r"^api/v2/", include("geonode.facets.urls")),
re_path(r"^api/v2/facets", include("geonode.facets.urls")),
re_path(r"^api/v2/", include("geonode.assets.urls")),
# metadata views
re_path(r"^api/v2/", include("geonode.metadata.api.urls")),
re_path(r"^api/v2/metadata/", include("geonode.metadata.api.urls")),
re_path(r"", include(api.urls)),
re_path(
r"uploads/upload",
Expand All @@ -157,9 +155,6 @@
urlpatterns += [
re_path(r"^i18n/", include(django.conf.urls.i18n), name="i18n"),
re_path(r"^jsi18n/$", JavaScriptCatalog.as_view(), js_info_dict, name="javascript-catalog"),
]

urlpatterns += [ # '',
re_path(r"^showmetadata/", include("geonode.catalogue.metadataxsl.urls")),
]

Expand All @@ -178,6 +173,11 @@
re_path(r"^gs/", include("geonode.geoserver.urls")),
]

# router.urls is a cached property: keep this after every router.register()-triggering include above.
urlpatterns += [
re_path(r"^api/v2/", include(router.urls)),
]

if settings.NOTIFICATIONS_MODULE in settings.INSTALLED_APPS:
notifications_urls = f"{settings.NOTIFICATIONS_MODULE}.urls"
urlpatterns += [ # '',
Expand All @@ -195,7 +195,6 @@
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.LOCAL_MEDIA_URL, document_root=settings.MEDIA_ROOT)

# Internationalization Javascript
urlpatterns += [
re_path(r"^metadata_update_redirect$", views.metadata_update_redirect, name="metadata_update_redirect"),
]
Expand Down
Loading