From 4918fe4e24949371bf620a4392862ae5070753be Mon Sep 17 00:00:00 2001 From: Hao Liu <44379968+TheRealHaoLiu@users.noreply.github.com> Date: Wed, 28 Feb 2024 16:53:32 -0500 Subject: [PATCH] Add setting for configuring optional URL prefix for /api Add OPTIONAL_API_URLPATTERN_PREFIX setting examples: - if set to `''` (empty string) API pattern will be `/api` - if set to 'controller' API pattern will be `/api` AND `/api/controller` --- awx/api/urls/urls.py | 19 +++++++++++++------ awx/api/versioning.py | 4 ++++ .../tests/docs/test_swagger_generation.py | 12 ++++++------ awx/settings/defaults.py | 5 +++++ 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/awx/api/urls/urls.py b/awx/api/urls/urls.py index c2218e5ed865..6fcec65112c5 100644 --- a/awx/api/urls/urls.py +++ b/awx/api/urls/urls.py @@ -3,6 +3,7 @@ from __future__ import absolute_import, unicode_literals from django.urls import include, re_path +from django.conf import settings from awx import MODE from awx.api.generics import LoggedLoginView, LoggedLogoutView @@ -159,15 +160,21 @@ re_path(r'^receptor_addresses/', include(receptor_address_urls)), ] - app_name = 'api' urlpatterns = [ - re_path(r'^$', ApiRootView.as_view(), name='api_root_view'), - re_path(r'^(?P(v2))/', include(v2_urls)), - re_path(r'^login/$', LoggedLoginView.as_view(template_name='rest_framework/login.html', extra_context={'inside_login_context': True}), name='login'), - re_path(r'^logout/$', LoggedLogoutView.as_view(next_page='/api/', redirect_field_name='next'), name='logout'), - re_path(r'^o/', include(oauth2_root_urls)), + re_path(r'^(' + settings.OPTIONAL_API_URLPATTERN_PREFIX + '/)?$', ApiRootView.as_view(), name='api_root_view'), + re_path(r'^(' + settings.OPTIONAL_API_URLPATTERN_PREFIX + '/)?(?P(v2))/', include(v2_urls)), + re_path( + r'^(' + settings.OPTIONAL_API_URLPATTERN_PREFIX + '/)?login/$', + LoggedLoginView.as_view(template_name='rest_framework/login.html', extra_context={'inside_login_context': True}), + name='login', + ), + re_path( + r'^(' + settings.OPTIONAL_API_URLPATTERN_PREFIX + '/)?logout/$', LoggedLogoutView.as_view(next_page='/api/', redirect_field_name='next'), name='logout' + ), + re_path(r'^(' + settings.OPTIONAL_API_URLPATTERN_PREFIX + '/)?o/', include(oauth2_root_urls)), ] + if MODE == 'development': # Only include these if we are in the development environment from awx.api.swagger import schema_view diff --git a/awx/api/versioning.py b/awx/api/versioning.py index 9fc57ac71e5c..38bcd7780602 100644 --- a/awx/api/versioning.py +++ b/awx/api/versioning.py @@ -24,6 +24,10 @@ def drf_reverse(viewname, args=None, kwargs=None, request=None, format=None, **e else: url = _reverse(viewname, args, kwargs, request, format, **extra) + if settings.OPTIONAL_API_URLPATTERN_PREFIX and request: + if request._request.path.startswith(f"/api/{settings.OPTIONAL_API_URLPATTERN_PREFIX}/v2/"): + url = url.replace('/api/v2/', f"/api/{settings.OPTIONAL_API_URLPATTERN_PREFIX}/v2/") + return url diff --git a/awx/main/tests/docs/test_swagger_generation.py b/awx/main/tests/docs/test_swagger_generation.py index b480e4562ee6..ae0baa0b0174 100644 --- a/awx/main/tests/docs/test_swagger_generation.py +++ b/awx/main/tests/docs/test_swagger_generation.py @@ -100,12 +100,12 @@ def test_sanity(self, release, request): # for a reasonable number here; if this test starts failing, raise/lower the bounds paths = JSON['paths'] assert 250 < len(paths) < 375 - assert set(list(paths['/api/'].keys())) == set(['get', 'parameters']) - assert set(list(paths['/api/v2/'].keys())) == set(['get', 'parameters']) - assert set(list(sorted(paths['/api/v2/credentials/'].keys()))) == set(['get', 'post', 'parameters']) - assert set(list(sorted(paths['/api/v2/credentials/{id}/'].keys()))) == set(['delete', 'get', 'patch', 'put', 'parameters']) - assert set(list(paths['/api/v2/settings/'].keys())) == set(['get', 'parameters']) - assert set(list(paths['/api/v2/settings/{category_slug}/'].keys())) == set(['get', 'put', 'patch', 'delete', 'parameters']) + assert set(list(paths['/api/{var}'].keys())) == set(['get', 'parameters']) + assert set(list(paths['/api/{var}v2/'].keys())) == set(['get', 'parameters']) + assert set(list(sorted(paths['/api/{var}v2/credentials/'].keys()))) == set(['get', 'post', 'parameters']) + assert set(list(sorted(paths['/api/{var}v2/credentials/{id}/'].keys()))) == set(['delete', 'get', 'patch', 'put', 'parameters']) + assert set(list(paths['/api/{var}v2/settings/'].keys())) == set(['get', 'parameters']) + assert set(list(paths['/api/{var}v2/settings/{category_slug}/'].keys())) == set(['get', 'put', 'patch', 'delete', 'parameters']) @pytest.mark.parametrize( 'path', diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index 1e2fed59b9a4..a4472ced6ef6 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -1126,3 +1126,8 @@ settings_file = os.path.join(os.path.dirname(dynamic_config.__file__), 'dynamic_settings.py') include(settings_file) + +# Add a postfix to the API URL patterns +# example if set to '' API pattern will be /api +# example if set to 'controller' API pattern will be /api AND /api/controller +OPTIONAL_API_URLPATTERN_PREFIX = ''