fix: stabilize post-MVP travel-agent and itinerary workflows
This commit is contained in:
38
backend/server/main/tests.py
Normal file
38
backend/server/main/tests.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from django.contrib.auth import get_user_model
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.test import APIClient, APITestCase
|
||||
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class MCPTokenEndpointTests(APITestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
username="mcp-token-user",
|
||||
email="mcp-token@example.com",
|
||||
password="password123",
|
||||
)
|
||||
|
||||
def test_requires_authentication(self):
|
||||
unauthenticated_client = APIClient()
|
||||
response = unauthenticated_client.get("/auth/mcp-token/")
|
||||
self.assertIn(response.status_code, [401, 403])
|
||||
|
||||
def test_returns_token_for_authenticated_user(self):
|
||||
self.client.force_authenticate(user=self.user)
|
||||
response = self.client.get("/auth/mcp-token/")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("token", response.json())
|
||||
self.assertTrue(Token.objects.filter(user=self.user).exists())
|
||||
|
||||
def test_reuses_existing_token(self):
|
||||
existing_token = Token.objects.create(user=self.user)
|
||||
|
||||
self.client.force_authenticate(user=self.user)
|
||||
response = self.client.get("/auth/mcp-token/")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.json().get("token"), existing_token.key)
|
||||
self.assertEqual(Token.objects.filter(user=self.user).count(), 1)
|
||||
@@ -10,7 +10,12 @@ from users.views import (
|
||||
EnabledSocialProvidersView,
|
||||
DisablePasswordAuthenticationView,
|
||||
)
|
||||
from .views import get_csrf_token, get_public_url, serve_protected_media
|
||||
from .views import (
|
||||
get_csrf_token,
|
||||
get_mcp_api_token,
|
||||
get_public_url,
|
||||
serve_protected_media,
|
||||
)
|
||||
from drf_yasg.views import get_schema_view
|
||||
from drf_yasg import openapi
|
||||
from mcp_server.views import MCPServerStreamableHttpView
|
||||
@@ -48,6 +53,7 @@ urlpatterns = [
|
||||
),
|
||||
name="mcp_server_streamable_http_endpoint",
|
||||
),
|
||||
path("auth/mcp-token/", get_mcp_api_token, name="get_mcp_api_token"),
|
||||
path("auth/", include("allauth.headless.urls")),
|
||||
# Serve protected media files
|
||||
re_path(
|
||||
|
||||
@@ -5,21 +5,42 @@ from django.conf import settings
|
||||
from django.http import HttpResponse, HttpResponseForbidden
|
||||
from django.views.static import serve
|
||||
from adventures.utils.file_permissions import checkFilePermission
|
||||
from rest_framework.authentication import SessionAuthentication, TokenAuthentication
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.decorators import (
|
||||
api_view,
|
||||
authentication_classes,
|
||||
permission_classes,
|
||||
)
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
|
||||
|
||||
def get_csrf_token(request):
|
||||
csrf_token = get_token(request)
|
||||
return JsonResponse({'csrfToken': csrf_token})
|
||||
return JsonResponse({"csrfToken": csrf_token})
|
||||
|
||||
|
||||
def get_public_url(request):
|
||||
return JsonResponse({'PUBLIC_URL': getenv('PUBLIC_URL')})
|
||||
return JsonResponse({"PUBLIC_URL": getenv("PUBLIC_URL")})
|
||||
|
||||
|
||||
@api_view(["GET"])
|
||||
@authentication_classes([SessionAuthentication, TokenAuthentication])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def get_mcp_api_token(request):
|
||||
token, _ = Token.objects.get_or_create(user=request.user)
|
||||
return Response({"token": token.key})
|
||||
|
||||
|
||||
protected_paths = ["images/", "attachments/"]
|
||||
|
||||
protected_paths = ['images/', 'attachments/']
|
||||
|
||||
def serve_protected_media(request, path):
|
||||
if any([path.startswith(protected_path) for protected_path in protected_paths]):
|
||||
image_id = path.split('/')[1]
|
||||
image_id = path.split("/")[1]
|
||||
user = request.user
|
||||
media_type = path.split('/')[0] + '/'
|
||||
media_type = path.split("/")[0] + "/"
|
||||
if checkFilePermission(image_id, user, media_type):
|
||||
if settings.DEBUG:
|
||||
# In debug mode, serve the file directly
|
||||
@@ -27,8 +48,8 @@ def serve_protected_media(request, path):
|
||||
else:
|
||||
# In production, use X-Accel-Redirect to serve the file using Nginx
|
||||
response = HttpResponse()
|
||||
response['Content-Type'] = ''
|
||||
response['X-Accel-Redirect'] = '/protectedMedia/' + path
|
||||
response["Content-Type"] = ""
|
||||
response["X-Accel-Redirect"] = "/protectedMedia/" + path
|
||||
return response
|
||||
else:
|
||||
return HttpResponseForbidden()
|
||||
@@ -37,6 +58,6 @@ def serve_protected_media(request, path):
|
||||
return serve(request, path, document_root=settings.MEDIA_ROOT)
|
||||
else:
|
||||
response = HttpResponse()
|
||||
response['Content-Type'] = ''
|
||||
response['X-Accel-Redirect'] = '/protectedMedia/' + path
|
||||
return response
|
||||
response["Content-Type"] = ""
|
||||
response["X-Accel-Redirect"] = "/protectedMedia/" + path
|
||||
return response
|
||||
|
||||
Reference in New Issue
Block a user