from django.views.generic import DetailView, ListView, CreateView, UpdateView from django.shortcuts import get_object_or_404, render from django.core.serializers.json import DjangoJSONEncoder from django.urls import reverse from django.db.models import Q from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.contenttypes.models import ContentType from django.contrib import messages from django.http import JsonResponse, HttpResponseRedirect, HttpResponse from .models import Park, ParkArea from .forms import ParkForm from rides.models import Ride from core.views import SlugRedirectMixin from moderation.mixins import EditSubmissionMixin, PhotoSubmissionMixin, HistoryMixin from moderation.models import EditSubmission from cities_light.models import Country, Region, City def get_countries(request): query = request.GET.get('q', '') filter_parks = request.GET.get('filter_parks', 'false') == 'true' # Base query countries = Country.objects.filter(name__icontains=query) # Only filter by parks if explicitly requested if filter_parks: countries = countries.filter(park__isnull=False) countries = countries.distinct().values('id', 'name')[:10] return JsonResponse(list(countries), safe=False) def get_regions(request): query = request.GET.get('q', '') country = request.GET.get('country', '') filter_parks = request.GET.get('filter_parks', 'false') == 'true' if not country: return JsonResponse([], safe=False) # Base query regions = Region.objects.filter( Q(name__icontains=query) | Q(alternate_names__icontains=query), country__name__iexact=country ) # Only filter by parks if explicitly requested if filter_parks: regions = regions.filter(park__isnull=False) regions = regions.distinct().values('id', 'name')[:10] return JsonResponse(list(regions), safe=False) def get_cities(request): query = request.GET.get('q', '') region = request.GET.get('region', '') country = request.GET.get('country', '') filter_parks = request.GET.get('filter_parks', 'false') == 'true' if not region or not country: return JsonResponse([], safe=False) # Base query cities = City.objects.filter( Q(name__icontains=query) | Q(alternate_names__icontains=query), region__name__iexact=region, region__country__name__iexact=country ) # Only filter by parks if explicitly requested if filter_parks: cities = cities.filter(park__isnull=False) cities = cities.distinct().values('id', 'name')[:10] return JsonResponse(list(cities), safe=False) class ParkCreateView(LoginRequiredMixin, CreateView): model = Park form_class = ParkForm template_name = 'parks/park_form.html' def prepare_changes_data(self, cleaned_data): data = cleaned_data.copy() # Convert model instances to IDs for JSON serialization if data.get('owner'): data['owner'] = data['owner'].id if data.get('country'): data['country'] = data['country'].id if data.get('region'): data['region'] = data['region'].id if data.get('city'): data['city'] = data['city'].id # Convert dates to ISO format strings if data.get('opening_date'): data['opening_date'] = data['opening_date'].isoformat() if data.get('closing_date'): data['closing_date'] = data['closing_date'].isoformat() return data def form_valid(self, form): changes = self.prepare_changes_data(form.cleaned_data) # Create submission record submission = EditSubmission.objects.create( user=self.request.user, content_type=ContentType.objects.get_for_model(Park), submission_type='CREATE', changes=changes, reason=self.request.POST.get('reason', ''), source=self.request.POST.get('source', '') ) # If user is moderator or above, auto-approve if self.request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']: self.object = form.save() submission.object_id = self.object.id submission.status = 'APPROVED' submission.handled_by = self.request.user submission.save() messages.success(self.request, f'Successfully created {self.object.name}') return HttpResponseRedirect(self.get_success_url()) messages.success(self.request, 'Your park submission has been sent for review') return HttpResponseRedirect(reverse('parks:park_list')) def get_success_url(self): return reverse('parks:park_detail', kwargs={'slug': self.object.slug}) class ParkUpdateView(LoginRequiredMixin, UpdateView): model = Park form_class = ParkForm template_name = 'parks/park_form.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['is_edit'] = True return context def prepare_changes_data(self, cleaned_data): data = cleaned_data.copy() # Convert model instances to IDs for JSON serialization if data.get('owner'): data['owner'] = data['owner'].id if data.get('country'): data['country'] = data['country'].id if data.get('region'): data['region'] = data['region'].id if data.get('city'): data['city'] = data['city'].id # Convert dates to ISO format strings if data.get('opening_date'): data['opening_date'] = data['opening_date'].isoformat() if data.get('closing_date'): data['closing_date'] = data['closing_date'].isoformat() return data def form_valid(self, form): changes = self.prepare_changes_data(form.cleaned_data) # Create submission record submission = EditSubmission.objects.create( user=self.request.user, content_type=ContentType.objects.get_for_model(Park), object_id=self.object.id, submission_type='EDIT', changes=changes, reason=self.request.POST.get('reason', ''), source=self.request.POST.get('source', '') ) # If user is moderator or above, auto-approve if self.request.user.role in ['MODERATOR', 'ADMIN', 'SUPERUSER']: self.object = form.save() submission.status = 'APPROVED' submission.handled_by = self.request.user submission.save() messages.success(self.request, f'Successfully updated {self.object.name}') return HttpResponseRedirect(self.get_success_url()) messages.success(self.request, f'Your changes to {self.object.name} have been sent for review') return HttpResponseRedirect(reverse('parks:park_detail', kwargs={'slug': self.object.slug})) def get_success_url(self): return reverse('parks:park_detail', kwargs={'slug': self.object.slug}) class ParkDetailView(SlugRedirectMixin, EditSubmissionMixin, PhotoSubmissionMixin, HistoryMixin, DetailView): model = Park template_name = 'parks/park_detail.html' context_object_name = 'park' def get_object(self, queryset=None): if queryset is None: queryset = self.get_queryset() slug = self.kwargs.get(self.slug_url_kwarg) # Try to get by current or historical slug return self.model.get_by_slug(slug)[0] def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['rides'] = Ride.objects.filter( park=self.object ).select_related('coaster_stats') context['areas'] = ParkArea.objects.filter(park=self.object) return context def get_redirect_url_pattern(self): return 'parks:park_detail' class ParkAreaDetailView(SlugRedirectMixin, EditSubmissionMixin, PhotoSubmissionMixin, HistoryMixin, DetailView): model = ParkArea template_name = 'parks/area_detail.html' context_object_name = 'area' slug_url_kwarg = 'area_slug' def get_object(self, queryset=None): if queryset is None: queryset = self.get_queryset() park_slug = self.kwargs.get('park_slug') area_slug = self.kwargs.get('area_slug') # Try to get by current or historical slug obj, is_old_slug = self.model.get_by_slug(area_slug) if obj.park.slug != park_slug: raise self.model.DoesNotExist("Park slug doesn't match") return obj def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['rides'] = Ride.objects.filter( area=self.object ).select_related('coaster_stats') return context def get_redirect_url_pattern(self): return 'parks:park_detail' def get_redirect_url_kwargs(self): return { 'park_slug': self.object.park.slug, 'area_slug': self.object.slug } class ParkListView(ListView): model = Park template_name = 'parks/park_list.html' context_object_name = 'parks' def get_queryset(self): queryset = Park.objects.select_related('owner', 'country', 'region', 'city').prefetch_related('photos', 'rides') search = self.request.GET.get('search', '').strip() country = self.request.GET.get('country', '').strip() region = self.request.GET.get('region', '').strip() city = self.request.GET.get('city', '').strip() statuses = self.request.GET.getlist('status') if search: queryset = queryset.filter( Q(name__icontains=search) | Q(location__icontains=search) ) if country: queryset = queryset.filter(country__name__icontains=country) if region: queryset = queryset.filter(region__name__icontains=region) if city: queryset = queryset.filter(city__name__icontains=city) if statuses: queryset = queryset.filter(status__in=statuses) return queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['current_filters'] = { 'search': self.request.GET.get('search', ''), 'country': self.request.GET.get('country', ''), 'region': self.request.GET.get('region', ''), 'city': self.request.GET.get('city', ''), 'statuses': self.request.GET.getlist('status') } return context def get(self, request, *args, **kwargs): # Check if this is an HTMX request if request.htmx: # If it is, return just the parks list partial self.template_name = 'parks/partials/park_list.html' return super().get(request, *args, **kwargs)