Skip to content

Commit df30c51

Browse files
committed
temp
1 parent 94c836a commit df30c51

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
@@ -121,7 +121,7 @@
121121
API_ROOT_REWRITE_HEADER = None
122122

123123
# Enable Pulp v4 API namespace
124-
ENABLE_V4_API = False
124+
ENABLE_V4_API = True
125125

126126
# Application definition
127127

@@ -216,7 +216,7 @@
216216
"rest_framework.authentication.SessionAuthentication",
217217
),
218218
"UPLOADED_FILES_USE_URL": False,
219-
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.NamespaceVersioning",
219+
"DEFAULT_VERSIONING_CLASS": "pulpcore.middleware.NamespaceVersioning",
220220
"DEFAULT_VERSION": "v3",
221221
"ALLOWED_VERSIONS": ["v3", "v4"],
222222
"DEFAULT_SCHEMA_CLASS": "pulpcore.openapi.PulpAutoSchema",
@@ -663,6 +663,7 @@ def otel_middleware_hook(settings):
663663
api_root = "/<path:api_root>/"
664664
else:
665665
api_root = settings.API_ROOT
666+
666667
settings.set("V3_API_ROOT", api_root + "api/v3/") # Not user configurable
667668
settings.set("V3_DOMAIN_API_ROOT", api_root + "<slug:pulp_domain>/api/v3/")
668669
settings.set("V3_API_ROOT_NO_FRONT_SLASH", settings.V3_API_ROOT.lstrip("/"))
@@ -672,3 +673,8 @@ def otel_middleware_hook(settings):
672673
settings.set("V4_DOMAIN_API_ROOT", api_root + "<slug:pulp_domain>/api/v4/")
673674
settings.set("V4_API_ROOT_NO_FRONT_SLASH", settings.V4_API_ROOT.lstrip("/"))
674675
settings.set("V4_DOMAIN_API_ROOT_NO_FRONT_SLASH", settings.V4_DOMAIN_API_ROOT.lstrip("/"))
676+
677+
if settings.API_ROOT_REWRITE_HEADER:
678+
V3_API_ROOT = settings.V3_API_ROOT.replace("/<path:api_root>/", settings.API_ROOT)
679+
else:
680+
V3_API_ROOT = settings.V3_API_ROOT

pulpcore/middleware.py

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

44
from django.http.response import Http404
55
from django.conf import settings
6-
from django.core.exceptions import MiddlewareNotUsed
6+
from django.core import exceptions as django_exceptions
7+
8+
from rest_framework.versioning import BaseVersioning
79

810
from pulpcore.metrics import init_otel_meter
911
from pulpcore.app.models import Domain
@@ -69,7 +71,7 @@ class APIRootRewriteMiddleware:
6971

7072
def __init__(self, get_response):
7173
if not settings.API_ROOT_REWRITE_HEADER:
72-
raise MiddlewareNotUsed()
74+
raise django_exceptions.MiddlewareNotUsed()
7375
self.get_response = get_response
7476

7577
def __call__(self, request):
@@ -168,3 +170,51 @@ def __call__(self, request):
168170
x_task_diagnostics_var.reset(ctx_token)
169171
else:
170172
return self.get_response(request)
173+
174+
175+
class NamespaceVersioning(BaseVersioning):
176+
"""
177+
To the client this is the same style as `URLPathVersioning`.
178+
The difference is in the backend - this implementation uses
179+
Django's URL namespaces to determine the version.
180+
181+
An example URL conf that is namespaced into two separate versions
182+
183+
# users/urls.py
184+
urlpatterns = [
185+
path('/users/', users_list, name='users-list'),
186+
path('/users/<int:pk>/', users_detail, name='users-detail')
187+
]
188+
189+
# urls.py
190+
urlpatterns = [
191+
path('v1/', include('users.urls', namespace='v1')),
192+
path('v2/', include('users.urls', namespace='v2'))
193+
]
194+
195+
GET /1.0/something/ HTTP/1.1
196+
Host: example.com
197+
Accept: application/json
198+
"""
199+
200+
invalid_version_message = "Invalid version in URL path. Does not match any version namespace."
201+
202+
def determine_version(self, request, *args, **kwargs):
203+
resolver_match = getattr(request, "resolver_match", None)
204+
if resolver_match is None or not resolver_match.namespace:
205+
return self.default_version
206+
207+
# Allow for possibly nested namespaces.
208+
possible_versions = resolver_match.namespace.split(":")
209+
for version in possible_versions:
210+
if self.is_allowed_version(version):
211+
return version
212+
raise django_exceptions.NotFound(self.invalid_version_message)
213+
214+
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
215+
if request.version is not None:
216+
viewname = self.get_versioned_viewname(viewname, request)
217+
return super().reverse(viewname, args, kwargs, request, format, **extra)
218+
219+
def get_versioned_viewname(self, viewname, request):
220+
return request.version + ":" + viewname

0 commit comments

Comments
 (0)