zeroed-some/localtoast / 02e5e89

Browse files

add cors options handling

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
02e5e89e4526c95e60ff115ad0ea2d3ebf42acbf
Parents
487fdab
Tree
31234b9

3 changed files

StatusFile+-
M backend/api/urls.py 3 0
M backend/api/views.py 72 1
M backend/localtoast/settings.py 31 5
backend/api/urls.pymodified
@@ -5,6 +5,9 @@ urlpatterns = [
55
     # Health check
66
     path('health/', views.health_check, name='health_check'),
77
     
8
+    # CORS test endpoint
9
+    path('cors-test/', views.cors_test, name='cors_test'),
10
+    
811
     # Restaurant endpoints
912
     path('restaurants/', views.RestaurantListCreateView.as_view(), name='restaurant_list_create'),
1013
     path('restaurants/nearby/', views.NearbyRestaurantsView.as_view(), name='restaurants_nearby'),
backend/api/views.pymodified
@@ -1,4 +1,4 @@
1
-from django.http import JsonResponse
1
+from django.http import JsonResponse, HttpResponse
22
 from django.utils import timezone
33
 from django.conf import settings
44
 from django.db.models import Q
@@ -39,6 +39,15 @@ def calculate_distance(lat1, lon1, lat2, lon2):
3939
 class NearbyRestaurantsView(APIView):
4040
     """Get restaurants near a location"""
4141
     
42
+    def options(self, request, *args, **kwargs):
43
+        """Handle preflight requests"""
44
+        response = HttpResponse()
45
+        response['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
46
+        response['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
47
+        response['Access-Control-Allow-Headers'] = 'Content-Type, Accept, X-Requested-With'
48
+        response['Access-Control-Max-Age'] = '3600'
49
+        return response
50
+    
4251
     def get(self, request):
4352
         lat = request.query_params.get('lat')
4453
         lng = request.query_params.get('lng')
@@ -93,6 +102,15 @@ class RestaurantListCreateView(generics.ListCreateAPIView):
93102
     queryset = Restaurant.objects.all()
94103
     serializer_class = RestaurantSerializer
95104
     
105
+    def options(self, request, *args, **kwargs):
106
+        """Handle preflight requests"""
107
+        response = HttpResponse()
108
+        response['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
109
+        response['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
110
+        response['Access-Control-Allow-Headers'] = 'Content-Type, Accept, X-Requested-With'
111
+        response['Access-Control-Max-Age'] = '3600'
112
+        return response
113
+    
96114
     def create(self, request, *args, **kwargs):
97115
         # Check if restaurant already exists
98116
         place_id = request.data.get('place_id')
@@ -109,11 +127,29 @@ class RestaurantDetailView(generics.RetrieveAPIView):
109127
     """Get detailed info about a restaurant"""
110128
     queryset = Restaurant.objects.all()
111129
     serializer_class = RestaurantDetailSerializer
130
+    
131
+    def options(self, request, *args, **kwargs):
132
+        """Handle preflight requests"""
133
+        response = HttpResponse()
134
+        response['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
135
+        response['Access-Control-Allow-Methods'] = 'GET, OPTIONS'
136
+        response['Access-Control-Allow-Headers'] = 'Content-Type, Accept, X-Requested-With'
137
+        response['Access-Control-Max-Age'] = '3600'
138
+        return response
112139
 
113140
 
114141
 class RestaurantRatingView(APIView):
115142
     """Add a rating to a restaurant or get all ratings"""
116143
     
144
+    def options(self, request, *args, **kwargs):
145
+        """Handle preflight requests"""
146
+        response = HttpResponse()
147
+        response['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
148
+        response['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
149
+        response['Access-Control-Allow-Headers'] = 'Content-Type, Accept, X-Requested-With'
150
+        response['Access-Control-Max-Age'] = '3600'
151
+        return response
152
+    
117153
     def get(self, request, pk):
118154
         try:
119155
             restaurant = Restaurant.objects.get(pk=pk)
@@ -152,6 +188,15 @@ class RestaurantRatingView(APIView):
152188
 class RestaurantToastStatusView(APIView):
153189
     """Update restaurant's toast status"""
154190
     
191
+    def options(self, request, *args, **kwargs):
192
+        """Handle preflight requests"""
193
+        response = HttpResponse()
194
+        response['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
195
+        response['Access-Control-Allow-Methods'] = 'PATCH, OPTIONS'
196
+        response['Access-Control-Allow-Headers'] = 'Content-Type, Accept, X-Requested-With'
197
+        response['Access-Control-Max-Age'] = '3600'
198
+        return response
199
+    
155200
     def patch(self, request, pk):
156201
         try:
157202
             restaurant = Restaurant.objects.get(pk=pk)
@@ -181,6 +226,15 @@ class RestaurantToastStatusView(APIView):
181226
 class SearchPlacesView(APIView):
182227
     """Search for places that might serve toast"""
183228
     
229
+    def options(self, request, *args, **kwargs):
230
+        """Handle preflight requests"""
231
+        response = HttpResponse()
232
+        response['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
233
+        response['Access-Control-Allow-Methods'] = 'GET, OPTIONS'
234
+        response['Access-Control-Allow-Headers'] = 'Content-Type, Accept, X-Requested-With'
235
+        response['Access-Control-Max-Age'] = '3600'
236
+        return response
237
+    
184238
     def get(self, request):
185239
         lat = request.query_params.get('lat')
186240
         lng = request.query_params.get('lng')
@@ -353,6 +407,23 @@ class SearchPlacesView(APIView):
353407
         ]
354408
 
355409
 
410
+@api_view(['GET', 'OPTIONS'])
411
+def cors_test(request):
412
+    """Test endpoint for CORS"""
413
+    if request.method == 'OPTIONS':
414
+        response = HttpResponse()
415
+        response['Access-Control-Allow-Origin'] = '*'
416
+        response['Access-Control-Allow-Methods'] = 'GET, OPTIONS'
417
+        response['Access-Control-Allow-Headers'] = '*'
418
+        return response
419
+    
420
+    return Response({
421
+        'status': 'CORS test successful',
422
+        'origin': request.headers.get('Origin', 'No origin header'),
423
+        'method': request.method
424
+    })
425
+
426
+
356427
 @api_view(['POST'])
357428
 def seed_data(request):
358429
     """Seed the database with sample restaurants"""
backend/localtoast/settings.pymodified
@@ -31,7 +31,7 @@ INSTALLED_APPS = [
3131
 
3232
 MIDDLEWARE = [
3333
     'django.middleware.security.SecurityMiddleware',
34
-    'corsheaders.middleware.CorsMiddleware',
34
+    'corsheaders.middleware.CorsMiddleware',  # Must be before CommonMiddleware
3535
     'django.middleware.common.CommonMiddleware',
3636
     'django.middleware.csrf.CsrfViewMiddleware',
3737
     'django.contrib.sessions.middleware.SessionMiddleware',
@@ -106,7 +106,7 @@ REST_FRAMEWORK = {
106106
     ],
107107
 }
108108
 
109
-# CORS settings
109
+# CORS settings - Updated for better compatibility
110110
 CORS_ALLOWED_ORIGINS = [
111111
     "http://localhost:3000",
112112
     "http://localhost:3001",
@@ -116,9 +116,35 @@ CORS_ALLOWED_ORIGINS = [
116116
     "https://localtoast.fyi",
117117
 ]
118118
 
119
-# Allow CORS during development
120
-if DEBUG:
121
-    CORS_ALLOW_ALL_ORIGINS = True
119
+# Add frontend URL from environment if provided
120
+if os.getenv('FRONTEND_URL'):
121
+    CORS_ALLOWED_ORIGINS.append(os.getenv('FRONTEND_URL'))
122
+
123
+# Explicit CORS configuration
124
+CORS_ALLOW_ALL_ORIGINS = False  # Never True in production
125
+CORS_ALLOW_CREDENTIALS = True
126
+CORS_PREFLIGHT_MAX_AGE = 86400
127
+
128
+CORS_ALLOW_METHODS = [
129
+    'DELETE',
130
+    'GET',
131
+    'OPTIONS',
132
+    'PATCH',
133
+    'POST',
134
+    'PUT',
135
+]
136
+
137
+CORS_ALLOW_HEADERS = [
138
+    'accept',
139
+    'accept-encoding',
140
+    'authorization',
141
+    'content-type',
142
+    'dnt',
143
+    'origin',
144
+    'user-agent',
145
+    'x-csrftoken',
146
+    'x-requested-with',
147
+]
122148
 
123149
 # Media files
124150
 MEDIA_URL = '/media/'