Skip to content

Commit 5e60dd5

Browse files
committed
temp
1 parent 6445757 commit 5e60dd5

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

pulpcore/app/settings.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
API_ROOT_REWRITE_HEADER = None
101101

102102
# Enable Pulp v4 API namespace
103-
ENABLE_V4_API = False
103+
ENABLE_V4_API = True
104104

105105
# Application definition
106106

@@ -195,7 +195,7 @@
195195
"rest_framework.authentication.SessionAuthentication",
196196
),
197197
"UPLOADED_FILES_USE_URL": False,
198-
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.NamespaceVersioning",
198+
"DEFAULT_VERSIONING_CLASS": "pulpcore.middleware.NamespaceVersioning",
199199
"DEFAULT_VERSION": "v3",
200200
"ALLOWED_VERSIONS": ["v3", "v4"],
201201
"DEFAULT_SCHEMA_CLASS": "pulpcore.openapi.PulpAutoSchema",
@@ -640,6 +640,7 @@ def otel_middleware_hook(settings):
640640
api_root = "/<path:api_root>/"
641641
else:
642642
api_root = settings.API_ROOT
643+
643644
settings.set("V3_API_ROOT", api_root + "api/v3/") # Not user configurable
644645
settings.set("V3_DOMAIN_API_ROOT", api_root + "<slug:pulp_domain>/api/v3/")
645646
settings.set("V3_API_ROOT_NO_FRONT_SLASH", settings.V3_API_ROOT.lstrip("/"))
@@ -649,3 +650,8 @@ def otel_middleware_hook(settings):
649650
settings.set("V4_DOMAIN_API_ROOT", api_root + "<slug:pulp_domain>/api/v4/")
650651
settings.set("V4_API_ROOT_NO_FRONT_SLASH", settings.V4_API_ROOT.lstrip("/"))
651652
settings.set("V4_DOMAIN_API_ROOT_NO_FRONT_SLASH", settings.V4_DOMAIN_API_ROOT.lstrip("/"))
653+
654+
if settings.API_ROOT_REWRITE_HEADER:
655+
V3_API_ROOT = settings.V3_API_ROOT.replace("/<path:api_root>/", settings.API_ROOT)
656+
else:
657+
V3_API_ROOT = settings.V3_API_ROOT

pulpcore/middleware.py

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
from django.http.response import Http404
88
from django.conf import settings
9-
from django.core.exceptions import MiddlewareNotUsed
9+
from django.core import exceptions as django_exceptions
10+
11+
from rest_framework.versioning import BaseVersioning
1012

1113
from pulpcore.metrics import init_otel_meter
1214
from pulpcore.app.models import Domain
@@ -72,7 +74,7 @@ class APIRootRewriteMiddleware:
7274

7375
def __init__(self, get_response):
7476
if not settings.API_ROOT_REWRITE_HEADER:
75-
raise MiddlewareNotUsed()
77+
raise django_exceptions.MiddlewareNotUsed()
7678
self.get_response = get_response
7779

7880
def __call__(self, request):
@@ -195,3 +197,51 @@ def __call__(self, request):
195197
x_task_diagnostics_var.reset(ctx_token)
196198
else:
197199
return self.get_response(request)
200+
201+
202+
class NamespaceVersioning(BaseVersioning):
203+
"""
204+
To the client this is the same style as `URLPathVersioning`.
205+
The difference is in the backend - this implementation uses
206+
Django's URL namespaces to determine the version.
207+
208+
An example URL conf that is namespaced into two separate versions
209+
210+
# users/urls.py
211+
urlpatterns = [
212+
path('/users/', users_list, name='users-list'),
213+
path('/users/<int:pk>/', users_detail, name='users-detail')
214+
]
215+
216+
# urls.py
217+
urlpatterns = [
218+
path('v1/', include('users.urls', namespace='v1')),
219+
path('v2/', include('users.urls', namespace='v2'))
220+
]
221+
222+
GET /1.0/something/ HTTP/1.1
223+
Host: example.com
224+
Accept: application/json
225+
"""
226+
227+
invalid_version_message = "Invalid version in URL path. Does not match any version namespace."
228+
229+
def determine_version(self, request, *args, **kwargs):
230+
resolver_match = getattr(request, "resolver_match", None)
231+
if resolver_match is None or not resolver_match.namespace:
232+
return self.default_version
233+
234+
# Allow for possibly nested namespaces.
235+
possible_versions = resolver_match.namespace.split(":")
236+
for version in possible_versions:
237+
if self.is_allowed_version(version):
238+
return version
239+
raise django_exceptions.NotFound(self.invalid_version_message)
240+
241+
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
242+
if request.version is not None:
243+
viewname = self.get_versioned_viewname(viewname, request)
244+
return super().reverse(viewname, args, kwargs, request, format, **extra)
245+
246+
def get_versioned_viewname(self, viewname, request):
247+
return request.version + ":" + viewname

0 commit comments

Comments
 (0)