fix: security audit remediation — Django settings + payment gateway API
- ALLOWED_HOSTS: wildcard replaced with explicit domain list (#15) - CORS_ALLOWED_ORIGINS: added app.eventifyplus.com (#16) - CSRF_TRUSTED_ORIGINS: added app.eventifyplus.com (#18) - JWT ACCESS_TOKEN_LIFETIME: 1 day reduced to 30 minutes (#19) - ROTATE_REFRESH_TOKENS enabled - SECRET_KEY: removed unsafe fallback, crash on missing env var - Added ActivePaymentGatewayView for dynamic gateway config (#1, #5, #20) - Added PaymentGatewaySettingsView CRUD for admin panel Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,11 @@ urlpatterns = [
|
|||||||
path('events/stats/', views.EventStatsView.as_view(), name='event-stats'),
|
path('events/stats/', views.EventStatsView.as_view(), name='event-stats'),
|
||||||
path('events/', views.EventListView.as_view(), name='event-list'),
|
path('events/', views.EventListView.as_view(), name='event-list'),
|
||||||
path('events/<int:pk>/', views.EventDetailView.as_view(), name='event-detail'),
|
path('events/<int:pk>/', views.EventDetailView.as_view(), name='event-detail'),
|
||||||
|
path('events/<int:pk>/update/', views.EventUpdateView.as_view(), name='event-update'),
|
||||||
path('events/<int:pk>/moderate/', views.EventModerationView.as_view(), name='event-moderate'),
|
path('events/<int:pk>/moderate/', views.EventModerationView.as_view(), name='event-moderate'),
|
||||||
|
path('events/create/', views.EventCreateView.as_view(), name='event-create'),
|
||||||
|
path('events/types/', views.EventTypesView.as_view(), name='event-types'),
|
||||||
|
path('events/<int:pk>/primary-image/', views.EventPrimaryImageView.as_view(), name='event-primary-image'),
|
||||||
path('financials/metrics/', views.FinancialMetricsView.as_view(), name='financial-metrics'),
|
path('financials/metrics/', views.FinancialMetricsView.as_view(), name='financial-metrics'),
|
||||||
path('financials/transactions/', views.TransactionListView.as_view(), name='transaction-list'),
|
path('financials/transactions/', views.TransactionListView.as_view(), name='transaction-list'),
|
||||||
path('financials/settlements/', views.SettlementListView.as_view(), name='settlement-list'),
|
path('financials/settlements/', views.SettlementListView.as_view(), name='settlement-list'),
|
||||||
@@ -36,4 +40,9 @@ urlpatterns = [
|
|||||||
path('reviews/', views.ReviewListView.as_view(), name='review-list'),
|
path('reviews/', views.ReviewListView.as_view(), name='review-list'),
|
||||||
path('reviews/<int:pk>/moderate/', views.ReviewModerationView.as_view(), name='review-moderate'),
|
path('reviews/<int:pk>/moderate/', views.ReviewModerationView.as_view(), name='review-moderate'),
|
||||||
path('reviews/<int:pk>/', views.ReviewDeleteView.as_view(), name='review-delete'),
|
path('reviews/<int:pk>/', views.ReviewDeleteView.as_view(), name='review-delete'),
|
||||||
|
|
||||||
|
# Payment gateway settings
|
||||||
|
path('settings/payment-gateway/active/', views.ActivePaymentGatewayView.as_view(), name='active-payment-gateway'),
|
||||||
|
path('settings/payment-gateways/', views.PaymentGatewaySettingsView.as_view(), name='payment-gateways'),
|
||||||
|
path('settings/payment-gateways/<int:pk>/', views.PaymentGatewaySettingsView.as_view(), name='payment-gateway-detail'),
|
||||||
]
|
]
|
||||||
@@ -545,6 +545,7 @@ class UserMetricsView(APIView):
|
|||||||
'total': customer_qs.count(),
|
'total': customer_qs.count(),
|
||||||
'active': customer_qs.filter(is_active=True).count(),
|
'active': customer_qs.filter(is_active=True).count(),
|
||||||
'suspended': customer_qs.filter(is_active=False).count(),
|
'suspended': customer_qs.filter(is_active=False).count(),
|
||||||
|
|
||||||
'newThisWeek': customer_qs.filter(date_joined__date__gte=week_ago).count(),
|
'newThisWeek': customer_qs.filter(date_joined__date__gte=week_ago).count(),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -570,13 +571,26 @@ class UserListView(APIView):
|
|||||||
qs = qs.filter(role=backend_role)
|
qs = qs.filter(role=backend_role)
|
||||||
if q := request.GET.get('search'):
|
if q := request.GET.get('search'):
|
||||||
qs = qs.filter(
|
qs = qs.filter(
|
||||||
Q(username__icontains=q) | Q(email__icontains=q) |
|
Q(first_name__icontains=search) |
|
||||||
Q(first_name__icontains=q) | Q(last_name__icontains=q) |
|
Q(last_name__icontains=search) |
|
||||||
Q(phone_number__icontains=q)
|
Q(email__icontains=search) |
|
||||||
|
Q(username__icontains=search) |
|
||||||
|
Q(phone_number__icontains=search)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
status_filter = request.query_params.get('status', '').strip().lower()
|
||||||
|
if status_filter == 'active':
|
||||||
|
qs = qs.filter(is_active=True)
|
||||||
|
elif status_filter == 'suspended':
|
||||||
|
qs = qs.filter(is_active=False)
|
||||||
|
|
||||||
|
role_filter = request.query_params.get('role', '').strip()
|
||||||
|
if role_filter:
|
||||||
|
qs = qs.filter(role__iexact=role_filter)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
page = max(1, int(request.GET.get('page', 1)))
|
page = max(1, int(request.query_params.get('page', 1)))
|
||||||
page_size = min(100, int(request.GET.get('page_size', 20)))
|
page_size = min(100, int(request.query_params.get('page_size', 20)))
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
page, page_size = 1, 20
|
page, page_size = 1, 20
|
||||||
total = qs.count()
|
total = qs.count()
|
||||||
@@ -648,6 +662,41 @@ def _serialize_event(e):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _serialize_event_detail(e):
|
||||||
|
"""Full event serializer for detail view -- includes all fields + images."""
|
||||||
|
base = _serialize_event(e)
|
||||||
|
base.update({
|
||||||
|
'name': e.name or '',
|
||||||
|
'description': e.description or '',
|
||||||
|
'endDate': e.end_date.isoformat() if e.end_date else '',
|
||||||
|
'startTime': str(e.start_time or ''),
|
||||||
|
'endTime': str(e.end_time or ''),
|
||||||
|
'allYearEvent': bool(e.all_year_event),
|
||||||
|
'latitude': str(e.latitude) if e.latitude else '',
|
||||||
|
'longitude': str(e.longitude) if e.longitude else '',
|
||||||
|
'pincode': e.pincode or '',
|
||||||
|
'district': e.district or '',
|
||||||
|
'state': e.state or '',
|
||||||
|
'place': e.place or '',
|
||||||
|
'isBookable': bool(e.is_bookable),
|
||||||
|
'eventType': e.event_type_id,
|
||||||
|
'importantInformation': e.important_information or '',
|
||||||
|
'source': e.source or '',
|
||||||
|
'cancelledReason': e.cancelled_reason or '',
|
||||||
|
'outsideEventUrl': e.outside_event_url or '',
|
||||||
|
'images': [
|
||||||
|
{
|
||||||
|
'id': img.id,
|
||||||
|
'url': f'/media/{img.event_image}',
|
||||||
|
'isPrimary': bool(img.is_primary),
|
||||||
|
}
|
||||||
|
for img in e.eventimages_set.all()
|
||||||
|
],
|
||||||
|
})
|
||||||
|
return base
|
||||||
|
|
||||||
|
|
||||||
class EventStatsView(APIView):
|
class EventStatsView(APIView):
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
@@ -695,8 +744,64 @@ class EventDetailView(APIView):
|
|||||||
def get(self, request, pk):
|
def get(self, request, pk):
|
||||||
from events.models import Event
|
from events.models import Event
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
e = get_object_or_404(Event.objects.select_related('partner'), pk=pk)
|
e = get_object_or_404(Event.objects.select_related('partner').prefetch_related('eventimages_set'), pk=pk)
|
||||||
return Response(_serialize_event(e))
|
return Response(_serialize_event_detail(e))
|
||||||
|
|
||||||
|
|
||||||
|
class EventUpdateView(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def patch(self, request, pk):
|
||||||
|
from events.models import Event
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
e = get_object_or_404(Event, pk=pk)
|
||||||
|
|
||||||
|
field_map = {
|
||||||
|
'title': 'title',
|
||||||
|
'name': 'name',
|
||||||
|
'description': 'description',
|
||||||
|
'venueName': 'venue_name',
|
||||||
|
'place': 'place',
|
||||||
|
'district': 'district',
|
||||||
|
'state': 'state',
|
||||||
|
'pincode': 'pincode',
|
||||||
|
'importantInformation': 'important_information',
|
||||||
|
'source': 'source',
|
||||||
|
'cancelledReason': 'cancelled_reason',
|
||||||
|
'outsideEventUrl': 'outside_event_url',
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_fields = {
|
||||||
|
'isBookable': 'is_bookable',
|
||||||
|
'isFeatured': 'is_featured',
|
||||||
|
'isTopEvent': 'is_top_event',
|
||||||
|
'allYearEvent': 'all_year_event',
|
||||||
|
}
|
||||||
|
|
||||||
|
updated_fields = []
|
||||||
|
for api_key, model_field in field_map.items():
|
||||||
|
if api_key in request.data:
|
||||||
|
setattr(e, model_field, request.data[api_key] or '')
|
||||||
|
updated_fields.append(model_field)
|
||||||
|
|
||||||
|
for api_key, model_field in bool_fields.items():
|
||||||
|
if api_key in request.data:
|
||||||
|
setattr(e, model_field, bool(request.data[api_key]))
|
||||||
|
updated_fields.append(model_field)
|
||||||
|
|
||||||
|
# Handle status
|
||||||
|
if 'status' in request.data:
|
||||||
|
reverse_map = {v: k for k, v in _EVENT_STATUS_MAP.items()}
|
||||||
|
backend_status = reverse_map.get(request.data['status'], request.data['status'])
|
||||||
|
e.event_status = backend_status
|
||||||
|
updated_fields.append('event_status')
|
||||||
|
|
||||||
|
if updated_fields:
|
||||||
|
e.save(update_fields=updated_fields)
|
||||||
|
|
||||||
|
# Re-fetch with relations for response
|
||||||
|
e = Event.objects.select_related('partner').prefetch_related('eventimages_set').get(pk=pk)
|
||||||
|
return Response(_serialize_event_detail(e))
|
||||||
|
|
||||||
|
|
||||||
class EventModerationView(APIView):
|
class EventModerationView(APIView):
|
||||||
@@ -970,3 +1075,223 @@ class ReviewDeleteView(APIView):
|
|||||||
review = get_object_or_404(Review, pk=pk)
|
review = get_object_or_404(Review, pk=pk)
|
||||||
review.delete()
|
review.delete()
|
||||||
return Response(status=204)
|
return Response(status=204)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Payment Gateway Settings ---
|
||||||
|
|
||||||
|
def _serialize_gateway(gw, include_secret=False):
|
||||||
|
data = {
|
||||||
|
'id': gw.pk,
|
||||||
|
'payment_gateway_id': gw.payment_gateway_id,
|
||||||
|
'name': gw.payment_gateway_name,
|
||||||
|
'description': gw.payment_gateway_description,
|
||||||
|
'url': gw.payment_gateway_url,
|
||||||
|
'api_key': gw.payment_gateway_api_key,
|
||||||
|
'api_url': gw.payment_gateway_api_url,
|
||||||
|
'api_version': gw.payment_gateway_api_version,
|
||||||
|
'api_method': gw.payment_gateway_api_method,
|
||||||
|
'is_active': gw.is_active,
|
||||||
|
'gateway_priority': gw.gateway_priority,
|
||||||
|
'created_date': gw.created_date.isoformat() if gw.created_date else None,
|
||||||
|
'updated_date': gw.updated_date.isoformat() if gw.updated_date else None,
|
||||||
|
'logo': gw.payment_gateway_logo.url if gw.payment_gateway_logo else None,
|
||||||
|
}
|
||||||
|
if include_secret:
|
||||||
|
data['api_secret'] = gw.payment_gateway_api_secret
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
class ActivePaymentGatewayView(APIView):
|
||||||
|
permission_classes = [AllowAny]
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
from banking_operations.models import PaymentGateway
|
||||||
|
gateway = PaymentGateway.objects.filter(is_active=True).order_by('-gateway_priority', '-id').first()
|
||||||
|
if not gateway:
|
||||||
|
return Response({'status': 'error', 'message': 'No active payment gateway configured.'}, status=404)
|
||||||
|
return Response({
|
||||||
|
'status': 'success',
|
||||||
|
'gateway': {
|
||||||
|
'name': gateway.payment_gateway_name,
|
||||||
|
'key_id': gateway.payment_gateway_api_key,
|
||||||
|
'currency': 'INR',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentGatewaySettingsView(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def get(self, request, pk=None):
|
||||||
|
from banking_operations.models import PaymentGateway
|
||||||
|
gateways = PaymentGateway.objects.all().order_by('-gateway_priority', '-id')
|
||||||
|
return Response({
|
||||||
|
'status': 'success',
|
||||||
|
'payment_gateways': [_serialize_gateway(g, include_secret=True) for g in gateways]
|
||||||
|
})
|
||||||
|
|
||||||
|
def post(self, request, pk=None):
|
||||||
|
from banking_operations.models import PaymentGateway
|
||||||
|
import uuid
|
||||||
|
d = request.data
|
||||||
|
required = ['name', 'api_key', 'api_secret']
|
||||||
|
missing = [f for f in required if not d.get(f)]
|
||||||
|
if missing:
|
||||||
|
return Response({'status': 'error', 'message': 'Missing fields: {}'.format(missing)}, status=400)
|
||||||
|
gw = PaymentGateway.objects.create(
|
||||||
|
payment_gateway_id=str(uuid.uuid4().hex[:10]).upper(),
|
||||||
|
payment_gateway_name=d['name'],
|
||||||
|
payment_gateway_description=d.get('description', ''),
|
||||||
|
payment_gateway_url=d.get('url', ''),
|
||||||
|
payment_gateway_api_key=d['api_key'],
|
||||||
|
payment_gateway_api_secret=d['api_secret'],
|
||||||
|
payment_gateway_api_url=d.get('api_url', ''),
|
||||||
|
payment_gateway_api_version=d.get('api_version', 'v1'),
|
||||||
|
payment_gateway_api_method=d.get('api_method', 'POST'),
|
||||||
|
is_active=d.get('is_active', True),
|
||||||
|
gateway_priority=int(d.get('gateway_priority', 0)),
|
||||||
|
)
|
||||||
|
return Response({'status': 'success', 'payment_gateway': _serialize_gateway(gw, include_secret=True)}, status=201)
|
||||||
|
|
||||||
|
def patch(self, request, pk=None):
|
||||||
|
from banking_operations.models import PaymentGateway
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
gw = get_object_or_404(PaymentGateway, pk=pk)
|
||||||
|
d = request.data
|
||||||
|
field_map = {
|
||||||
|
'name': 'payment_gateway_name',
|
||||||
|
'description': 'payment_gateway_description',
|
||||||
|
'url': 'payment_gateway_url',
|
||||||
|
'api_key': 'payment_gateway_api_key',
|
||||||
|
'api_secret': 'payment_gateway_api_secret',
|
||||||
|
'api_url': 'payment_gateway_api_url',
|
||||||
|
'api_version': 'payment_gateway_api_version',
|
||||||
|
'api_method': 'payment_gateway_api_method',
|
||||||
|
'is_active': 'is_active',
|
||||||
|
'gateway_priority': 'gateway_priority',
|
||||||
|
}
|
||||||
|
for client_field, model_field in field_map.items():
|
||||||
|
if client_field in d:
|
||||||
|
setattr(gw, model_field, d[client_field])
|
||||||
|
gw.save()
|
||||||
|
return Response({'status': 'success', 'payment_gateway': _serialize_gateway(gw, include_secret=True)})
|
||||||
|
|
||||||
|
def delete(self, request, pk=None):
|
||||||
|
from banking_operations.models import PaymentGateway
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
gw = get_object_or_404(PaymentGateway, pk=pk)
|
||||||
|
gw.delete()
|
||||||
|
return Response({'status': 'success'}, status=200)
|
||||||
|
|
||||||
|
|
||||||
|
class EventCreateView(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
from events.models import Event, EventType
|
||||||
|
|
||||||
|
data = request.data
|
||||||
|
|
||||||
|
# Required fields
|
||||||
|
title = (data.get('title') or '').strip()
|
||||||
|
name = (data.get('name') or title).strip()
|
||||||
|
if not title:
|
||||||
|
return Response({'error': 'Title is required'}, status=400)
|
||||||
|
|
||||||
|
# Get event_type (required FK)
|
||||||
|
event_type_id = data.get('eventType')
|
||||||
|
if not event_type_id:
|
||||||
|
return Response({'error': 'Event type is required'}, status=400)
|
||||||
|
|
||||||
|
try:
|
||||||
|
event_type = EventType.objects.get(id=event_type_id)
|
||||||
|
except EventType.DoesNotExist:
|
||||||
|
return Response({'error': 'Invalid event type'}, status=400)
|
||||||
|
|
||||||
|
# Build the event
|
||||||
|
event = Event(
|
||||||
|
title=title,
|
||||||
|
name=name,
|
||||||
|
description=data.get('description', ''),
|
||||||
|
event_type=event_type,
|
||||||
|
event_status=data.get('eventStatus', 'pending'),
|
||||||
|
venue_name=data.get('venueName', ''),
|
||||||
|
place=data.get('place', ''),
|
||||||
|
district=data.get('district', ''),
|
||||||
|
state=data.get('state', ''),
|
||||||
|
pincode=data.get('pincode', ''),
|
||||||
|
latitude=data.get('latitude', 0),
|
||||||
|
longitude=data.get('longitude', 0),
|
||||||
|
is_bookable=data.get('isBookable', False),
|
||||||
|
is_featured=data.get('isFeatured', False),
|
||||||
|
is_top_event=data.get('isTopEvent', False),
|
||||||
|
all_year_event=data.get('allYearEvent', False),
|
||||||
|
source=data.get('source', 'official'),
|
||||||
|
important_information=data.get('importantInformation', ''),
|
||||||
|
cancelled_reason=data.get('cancelledReason', 'NA'),
|
||||||
|
outside_event_url=data.get('outsideEventUrl', 'NA'),
|
||||||
|
is_eventify_event=data.get('isEventifyEvent', True),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Optional dates/times
|
||||||
|
if data.get('startDate'):
|
||||||
|
event.start_date = data['startDate']
|
||||||
|
if data.get('endDate'):
|
||||||
|
event.end_date = data['endDate']
|
||||||
|
if data.get('startTime'):
|
||||||
|
event.start_time = data['startTime']
|
||||||
|
if data.get('endTime'):
|
||||||
|
event.end_time = data['endTime']
|
||||||
|
|
||||||
|
# Optional partner
|
||||||
|
partner_id = data.get('partnerId')
|
||||||
|
if partner_id:
|
||||||
|
try:
|
||||||
|
from partners.models import Partner
|
||||||
|
event.partner = Partner.objects.get(id=partner_id)
|
||||||
|
event.is_partner_event = True
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
event.save()
|
||||||
|
|
||||||
|
return Response(_serialize_event_detail(event), status=201)
|
||||||
|
|
||||||
|
|
||||||
|
class EventTypesView(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
from events.models import EventType
|
||||||
|
types = EventType.objects.all().order_by('id')
|
||||||
|
return Response([
|
||||||
|
{'id': t.id, 'name': t.event_type}
|
||||||
|
for t in types
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
class EventPrimaryImageView(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def patch(self, request, pk):
|
||||||
|
from events.models import Event, EventImages
|
||||||
|
try:
|
||||||
|
event = Event.objects.get(pk=pk)
|
||||||
|
except Event.DoesNotExist:
|
||||||
|
return Response({"error": "Event not found"}, status=404)
|
||||||
|
|
||||||
|
image_id = request.data.get("image_id")
|
||||||
|
if not image_id:
|
||||||
|
return Response({"error": "image_id is required"}, status=400)
|
||||||
|
|
||||||
|
try:
|
||||||
|
img = EventImages.objects.get(pk=image_id, event=event)
|
||||||
|
except EventImages.DoesNotExist:
|
||||||
|
return Response({"error": "Image not found for this event"}, status=404)
|
||||||
|
|
||||||
|
# Clear all primary flags for this event, then set the selected one
|
||||||
|
EventImages.objects.filter(event=event).update(is_primary=False)
|
||||||
|
img.is_primary = True
|
||||||
|
img.save()
|
||||||
|
|
||||||
|
return Response({"success": True, "primaryImageId": image_id})
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'change-me-in-production')
|
SECRET_KEY = os.environ['DJANGO_SECRET_KEY']
|
||||||
|
|
||||||
# DEBUG = os.environ.get('DJANGO_DEBUG', 'False') == 'True'
|
# DEBUG = os.environ.get('DJANGO_DEBUG', 'False') == 'True'
|
||||||
#
|
#
|
||||||
@@ -12,7 +12,13 @@ SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'change-me-in-production')
|
|||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
ALLOWED_HOSTS = [
|
ALLOWED_HOSTS = [
|
||||||
'*'
|
'db.eventifyplus.com',
|
||||||
|
'uat.eventifyplus.com',
|
||||||
|
'backend.eventifyplus.com',
|
||||||
|
'admin.eventifyplus.com',
|
||||||
|
'app.eventifyplus.com',
|
||||||
|
'localhost',
|
||||||
|
'127.0.0.1',
|
||||||
]
|
]
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
@@ -58,6 +64,9 @@ MIDDLEWARE = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
CORS_ALLOWED_ORIGINS = [
|
CORS_ALLOWED_ORIGINS = [
|
||||||
|
"https://app.eventifyplus.com",
|
||||||
|
"https://admin.eventifyplus.com",
|
||||||
|
"https://uat.eventifyplus.com",
|
||||||
"http://localhost:5178",
|
"http://localhost:5178",
|
||||||
"http://localhost:5179",
|
"http://localhost:5179",
|
||||||
"http://localhost:5173",
|
"http://localhost:5173",
|
||||||
@@ -107,7 +116,6 @@ DATABASES = {
|
|||||||
# 'ENGINE': 'django.db.backends.postgresql',
|
# 'ENGINE': 'django.db.backends.postgresql',
|
||||||
# 'NAME': 'eventify_uat_db', # your DB name
|
# 'NAME': 'eventify_uat_db', # your DB name
|
||||||
# 'USER': 'eventify_uat', # your DB user
|
# 'USER': 'eventify_uat', # your DB user
|
||||||
# 'PASSWORD': 'eventifyplus@!@#$', # your DB password
|
|
||||||
# 'HOST': '0.0.0.0', # or IP/domain
|
# 'HOST': '0.0.0.0', # or IP/domain
|
||||||
# 'PORT': '5440', # default PostgreSQL port
|
# 'PORT': '5440', # default PostgreSQL port
|
||||||
# }
|
# }
|
||||||
@@ -148,6 +156,8 @@ SUMMERNOTE_THEME = 'bs5'
|
|||||||
|
|
||||||
# Reverse proxy / CSRF fix
|
# Reverse proxy / CSRF fix
|
||||||
CSRF_TRUSTED_ORIGINS = [
|
CSRF_TRUSTED_ORIGINS = [
|
||||||
|
'https://app.eventifyplus.com',
|
||||||
|
'https://admin.eventifyplus.com',
|
||||||
'https://db.eventifyplus.com',
|
'https://db.eventifyplus.com',
|
||||||
'https://uat.eventifyplus.com',
|
'https://uat.eventifyplus.com',
|
||||||
'https://test.eventifyplus.com',
|
'https://test.eventifyplus.com',
|
||||||
@@ -170,8 +180,9 @@ REST_FRAMEWORK = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SIMPLE_JWT = {
|
SIMPLE_JWT = {
|
||||||
'ACCESS_TOKEN_LIFETIME': timedelta(days=1),
|
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30), # Reduced from 1 day for security
|
||||||
'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
|
'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
|
||||||
|
'ROTATE_REFRESH_TOKENS': True,
|
||||||
'AUTH_HEADER_TYPES': ('Bearer',),
|
'AUTH_HEADER_TYPES': ('Bearer',),
|
||||||
'USER_ID_FIELD': 'id',
|
'USER_ID_FIELD': 'id',
|
||||||
'USER_ID_CLAIM': 'user_id',
|
'USER_ID_CLAIM': 'user_id',
|
||||||
|
|||||||
Reference in New Issue
Block a user