fix location add

This commit is contained in:
pacnpal
2024-11-05 15:11:45 +00:00
parent 491be57ab2
commit 11fccaaf06
7 changed files with 91 additions and 46 deletions

1
.gitignore vendored
View File

@@ -28,3 +28,4 @@ moderation/__pycache__
rides/__pycache__ rides/__pycache__
ssh_tools.jsonc ssh_tools.jsonc
thrillwiki/__pycache__/settings.cpython-312.pyc thrillwiki/__pycache__/settings.cpython-312.pyc
parks/__pycache__/views.cpython-312.pyc

View File

@@ -57,7 +57,7 @@ def upload_photo(request):
# Get the object instance # Get the object instance
try: try:
obj = content_type.get_object_for_this_type(id=object_id) obj = content_type.get_object_for_this_type(pk=object_id)
except Exception as e: except Exception as e:
return JsonResponse( return JsonResponse(
{ {
@@ -82,17 +82,17 @@ def upload_photo(request):
photo = Photo.objects.create( photo = Photo.objects.create(
image=request.FILES["image"], image=request.FILES["image"],
content_type=content_type, content_type=content_type,
object_id=obj.id, object_id=obj.pk,
uploaded_by=request.user, # Add the user who uploaded the photo uploaded_by=request.user, # Add the user who uploaded the photo
is_primary=not Photo.objects.filter( is_primary=not Photo.objects.filter(
content_type=content_type, object_id=obj.id content_type=content_type, object_id=obj.pk
).exists(), ).exists(),
is_approved=is_approved # Auto-approve if the user is a moderator, admin, or superuser is_approved=is_approved # Auto-approve if the user is a moderator, admin, or superuser
) )
return JsonResponse( return JsonResponse(
{ {
"id": photo.id, "id": photo.pk,
"url": photo.image.url, "url": photo.image.url,
"caption": photo.caption, "caption": photo.caption,
"is_primary": photo.is_primary, "is_primary": photo.is_primary,
@@ -113,7 +113,7 @@ def upload_photo(request):
def set_primary_photo(request, photo_id): def set_primary_photo(request, photo_id):
"""Set a photo as primary""" """Set a photo as primary"""
try: try:
photo = get_object_or_404(Photo, id=photo_id) photo = get_object_or_404(Photo, pk=photo_id)
# Check if user has permission to edit photos # Check if user has permission to edit photos
if not request.user.has_perm("media.change_photo"): if not request.user.has_perm("media.change_photo"):
@@ -137,7 +137,7 @@ def set_primary_photo(request, photo_id):
def update_caption(request, photo_id): def update_caption(request, photo_id):
"""Update a photo's caption""" """Update a photo's caption"""
try: try:
photo = get_object_or_404(Photo, id=photo_id) photo = get_object_or_404(Photo, pk=photo_id)
# Check if user has permission to edit photos # Check if user has permission to edit photos
if not request.user.has_perm("media.change_photo"): if not request.user.has_perm("media.change_photo"):
@@ -150,7 +150,7 @@ def update_caption(request, photo_id):
photo.caption = data.get("caption", "") photo.caption = data.get("caption", "")
photo.save() photo.save()
return JsonResponse({"id": photo.id, "caption": photo.caption}) return JsonResponse({"id": photo.pk, "caption": photo.caption})
except Exception as e: except Exception as e:
logger.error(f"Error in update_caption: {str(e)}", exc_info=True) logger.error(f"Error in update_caption: {str(e)}", exc_info=True)
@@ -162,7 +162,7 @@ def update_caption(request, photo_id):
def delete_photo(request, photo_id): def delete_photo(request, photo_id):
"""Delete a photo""" """Delete a photo"""
try: try:
photo = get_object_or_404(Photo, id=photo_id) photo = get_object_or_404(Photo, pk=photo_id)
# Check if user has permission to delete photos # Check if user has permission to delete photos
if not request.user.has_perm("media.delete_photo"): if not request.user.has_perm("media.delete_photo"):

View File

@@ -1,6 +1,7 @@
from django import forms from django import forms
from decimal import Decimal, InvalidOperation, ROUND_DOWN from decimal import Decimal, InvalidOperation, ROUND_DOWN
from .models import Park from .models import Park
from location.models import Location
class ParkForm(forms.ModelForm): class ParkForm(forms.ModelForm):
@@ -207,8 +208,14 @@ class ParkForm(forms.ModelForm):
'postal_code': self.cleaned_data.get('postal_code'), 'postal_code': self.cleaned_data.get('postal_code'),
} }
# Set location data to be saved with the park # Handle location: update if exists, create if not
park.set_location(**location_data) if park.location.exists():
location = park.location.first()
for key, value in location_data.items():
setattr(location, key, value)
location.save()
else:
Location.objects.create(content_object=park, **location_data)
if commit: if commit:
park.save() park.save()

View File

@@ -17,6 +17,7 @@ from moderation.mixins import EditSubmissionMixin, PhotoSubmissionMixin, History
from moderation.models import EditSubmission from moderation.models import EditSubmission
from media.models import Photo from media.models import Photo
from location.models import Location from location.models import Location
from reviews.models import Review # Import the Review model
def location_search(request): def location_search(request):
@@ -145,7 +146,7 @@ class ParkListView(ListView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
# Check if this is an HTMX request # Check if this is an HTMX request
if request.htmx: if hasattr(request, 'htmx') and getattr(request, 'htmx', False):
# If it is, return just the parks list partial # If it is, return just the parks list partial
self.template_name = "parks/partials/park_list.html" self.template_name = "parks/partials/park_list.html"
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
@@ -167,7 +168,7 @@ class ParkDetailView(
queryset = self.get_queryset() queryset = self.get_queryset()
slug = self.kwargs.get(self.slug_url_kwarg) slug = self.kwargs.get(self.slug_url_kwarg)
# Try to get by current or historical slug # Try to get by current or historical slug
return self.model.get_by_slug(slug)[0] return Park.get_by_slug(slug)[0]
def get_queryset(self): def get_queryset(self):
return super().get_queryset().prefetch_related( return super().get_queryset().prefetch_related(
@@ -186,6 +187,17 @@ class ParkDetailView(
'-status', # OPERATING will come before others '-status', # OPERATING will come before others
'name' 'name'
) )
# Check if the user has reviewed the park
if self.request.user.is_authenticated:
context["has_reviewed"] = Review.objects.filter(
user=self.request.user,
content_type=ContentType.objects.get_for_model(Park),
object_id=self.object.id
).exists()
else:
context["has_reviewed"] = False
return context return context
def get_redirect_url_pattern(self): def get_redirect_url_pattern(self):
@@ -214,8 +226,7 @@ class ParkCreateView(LoginRequiredMixin, CreateView):
data[field] = str(data[field]) data[field] = str(data[field])
return data return data
def form_valid(self, form): def normalize_coordinates(self, form):
# Normalize coordinates before saving
if form.cleaned_data.get("latitude"): if form.cleaned_data.get("latitude"):
lat = Decimal(str(form.cleaned_data["latitude"])) lat = Decimal(str(form.cleaned_data["latitude"]))
form.cleaned_data["latitude"] = lat.quantize(Decimal('0.000001'), rounding=ROUND_DOWN) form.cleaned_data["latitude"] = lat.quantize(Decimal('0.000001'), rounding=ROUND_DOWN)
@@ -223,6 +234,10 @@ class ParkCreateView(LoginRequiredMixin, CreateView):
lon = Decimal(str(form.cleaned_data["longitude"])) lon = Decimal(str(form.cleaned_data["longitude"]))
form.cleaned_data["longitude"] = lon.quantize(Decimal('0.000001'), rounding=ROUND_DOWN) form.cleaned_data["longitude"] = lon.quantize(Decimal('0.000001'), rounding=ROUND_DOWN)
def form_valid(self, form):
# Normalize coordinates before saving
self.normalize_coordinates(form)
changes = self.prepare_changes_data(form.cleaned_data) changes = self.prepare_changes_data(form.cleaned_data)
# Create submission record # Create submission record
@@ -236,7 +251,7 @@ class ParkCreateView(LoginRequiredMixin, CreateView):
) )
# If user is moderator or above, auto-approve # If user is moderator or above, auto-approve
if self.request.user.role in ["MODERATOR", "ADMIN", "SUPERUSER"]: if hasattr(self.request.user, 'role') and getattr(self.request.user, 'role', None) in ["MODERATOR", "ADMIN", "SUPERUSER"]:
try: try:
self.object = form.save() self.object = form.save()
submission.object_id = self.object.id submission.object_id = self.object.id
@@ -337,8 +352,7 @@ class ParkUpdateView(LoginRequiredMixin, UpdateView):
data[field] = str(data[field]) data[field] = str(data[field])
return data return data
def form_valid(self, form): def normalize_coordinates(self, form):
# Normalize coordinates before saving
if form.cleaned_data.get("latitude"): if form.cleaned_data.get("latitude"):
lat = Decimal(str(form.cleaned_data["latitude"])) lat = Decimal(str(form.cleaned_data["latitude"]))
form.cleaned_data["latitude"] = lat.quantize(Decimal('0.000001'), rounding=ROUND_DOWN) form.cleaned_data["latitude"] = lat.quantize(Decimal('0.000001'), rounding=ROUND_DOWN)
@@ -346,6 +360,10 @@ class ParkUpdateView(LoginRequiredMixin, UpdateView):
lon = Decimal(str(form.cleaned_data["longitude"])) lon = Decimal(str(form.cleaned_data["longitude"]))
form.cleaned_data["longitude"] = lon.quantize(Decimal('0.000001'), rounding=ROUND_DOWN) form.cleaned_data["longitude"] = lon.quantize(Decimal('0.000001'), rounding=ROUND_DOWN)
def form_valid(self, form):
# Normalize coordinates before saving
self.normalize_coordinates(form)
changes = self.prepare_changes_data(form.cleaned_data) changes = self.prepare_changes_data(form.cleaned_data)
# Create submission record # Create submission record
@@ -360,7 +378,7 @@ class ParkUpdateView(LoginRequiredMixin, UpdateView):
) )
# If user is moderator or above, auto-approve # If user is moderator or above, auto-approve
if self.request.user.role in ["MODERATOR", "ADMIN", "SUPERUSER"]: if hasattr(self.request.user, 'role') and getattr(self.request.user, 'role', None) in ["MODERATOR", "ADMIN", "SUPERUSER"]:
try: try:
self.object = form.save() self.object = form.save()
submission.status = "APPROVED" submission.status = "APPROVED"
@@ -464,7 +482,7 @@ class ParkAreaDetailView(
park_slug = self.kwargs.get("park_slug") park_slug = self.kwargs.get("park_slug")
area_slug = self.kwargs.get("area_slug") area_slug = self.kwargs.get("area_slug")
# Try to get by current or historical slug # Try to get by current or historical slug
obj, is_old_slug = self.model.get_by_slug(area_slug) obj, is_old_slug = ParkArea.get_by_slug(area_slug)
if obj.park.slug != park_slug: if obj.park.slug != park_slug:
raise self.model.DoesNotExist("Park slug doesn't match") raise self.model.DoesNotExist("Park slug doesn't match")
return obj return obj

View File

@@ -2948,6 +2948,10 @@ select {
padding: 0.125rem; padding: 0.125rem;
} }
.p-1 {
padding: 0.25rem;
}
.p-1\.5 { .p-1\.5 {
padding: 0.375rem; padding: 0.375rem;
} }
@@ -3912,6 +3916,11 @@ select {
line-height: 1.5rem; line-height: 1.5rem;
} }
.sm\:text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
}
.sm\:text-sm { .sm\:text-sm {
font-size: 0.875rem; font-size: 0.875rem;
line-height: 1.25rem; line-height: 1.25rem;
@@ -3926,11 +3935,6 @@ select {
font-size: 0.75rem; font-size: 0.75rem;
line-height: 1rem; line-height: 1rem;
} }
.sm\:text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
}
} }
@media (min-width: 768px) { @media (min-width: 768px) {
@@ -3972,11 +3976,6 @@ select {
line-height: 1; line-height: 1;
} }
.md\:text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
}
.md\:text-lg { .md\:text-lg {
font-size: 1.125rem; font-size: 1.125rem;
line-height: 1.75rem; line-height: 1.75rem;

View File

@@ -33,22 +33,42 @@
<i class="mr-1 fas fa-camera"></i>Upload Photo <i class="mr-1 fas fa-camera"></i>Upload Photo
</button> </button>
{% endif %} {% endif %}
<!-- Add/Edit Review Button -->
{% if not park.reviews.exists %}
<a href="{% url 'reviews:add_review' park.slug %}"
class="transition-transform btn-secondary hover:scale-105">
<i class="mr-1 fas fa-star"></i>Add Review
</a>
{% else %}
{% if user.has_reviewed_park(park) %}
<a href="{% url 'reviews:edit_review' park.slug %}"
class="transition-transform btn-secondary hover:scale-105">
<i class="mr-1 fas fa-star"></i>Edit Review
</a>
{% else %}
<a href="{% url 'reviews:add_review' park.slug %}"
class="transition-transform btn-secondary hover:scale-105">
<i class="mr-1 fas fa-star"></i>Add Review
</a>
{% endif %}
{% endif %}
</div> </div>
{% endif %} {% endif %}
<!-- Header Grid --> <!-- Header Grid -->
<div class="grid grid-cols-2 gap-4 mb-8 sm:grid-cols-12"> <div class="grid grid-cols-2 gap-2 mb-6 sm:grid-cols-12">
<!-- Park Info Card --> <!-- Park Info Card -->
<div class="flex flex-col items-center justify-center h-full col-span-2 p-4 text-center bg-white rounded-lg shadow-lg sm:col-span-3 dark:bg-gray-800"> <div class="flex flex-col items-center justify-center h-full col-span-2 p-3 text-center bg-white rounded-lg shadow-lg sm:col-span-3 dark:bg-gray-800">
<h1 class="text-2xl font-bold leading-tight text-gray-900 sm:text-lg lg:text-4xl md:text-lg dark:text-white">{{ park.name }}</h1> <h1 class="text-2xl font-bold leading-tight text-gray-900 sm:text-lg lg:text-4xl md:text-lg dark:text-white">{{ park.name }}</h1>
{% if park.formatted_location %} {% if park.formatted_location %}
<div class="flex items-center justify-center mt-2 text-sm text-gray-600 dark:text-gray-400"> <div class="flex items-center justify-center mt-1 text-sm text-gray-600 dark:text-gray-400">
<i class="mr-1 fas fa-map-marker-alt"></i> <i class="mr-1 fas fa-map-marker-alt"></i>
<p>{{ park.formatted_location }}</p> <p>{{ park.formatted_location }}</p>
</div> </div>
{% endif %} {% endif %}
<div class="flex flex-wrap items-center justify-center gap-2 mt-3"> <div class="flex flex-wrap items-center justify-center gap-1 mt-2">
<span class="status-badge text-xs sm:text-sm font-medium py-1 px-3 {% if park.status == 'OPERATING' %}status-operating <span class="status-badge text-xs sm:text-sm font-medium py-1 px-2 {% if park.status == 'OPERATING' %}status-operating
{% elif park.status == 'CLOSED_TEMP' or park.status == 'CLOSED_PERM' %}status-closed {% elif park.status == 'CLOSED_TEMP' or park.status == 'CLOSED_PERM' %}status-closed
{% elif park.status == 'UNDER_CONSTRUCTION' %}status-construction {% elif park.status == 'UNDER_CONSTRUCTION' %}status-construction
{% elif park.status == 'DEMOLISHED' %}status-demolished {% elif park.status == 'DEMOLISHED' %}status-demolished
@@ -56,7 +76,7 @@
{{ park.get_status_display }} {{ park.get_status_display }}
</span> </span>
{% if park.average_rating %} {% if park.average_rating %}
<span class="flex items-center px-3 py-1 text-xs font-medium text-yellow-800 bg-yellow-100 sm:text-sm status-badge dark:bg-yellow-600 dark:text-yellow-50"> <span class="flex items-center px-2 py-1 text-xs font-medium text-yellow-800 bg-yellow-100 sm:text-sm status-badge dark:bg-yellow-600 dark:text-yellow-50">
<span class="mr-1 text-yellow-500 dark:text-yellow-200"></span> <span class="mr-1 text-yellow-500 dark:text-yellow-200"></span>
{{ park.average_rating|floatformat:1 }}/10 {{ park.average_rating|floatformat:1 }}/10
</span> </span>
@@ -65,31 +85,31 @@
</div> </div>
<!-- Stats and Quick Facts --> <!-- Stats and Quick Facts -->
<div class="grid h-full grid-cols-2 col-span-2 gap-4 sm:col-span-9"> <div class="grid h-full grid-cols-2 col-span-2 gap-2 sm:col-span-9">
<!-- Stats Column --> <!-- Stats Column -->
<div class="grid grid-cols-2 col-span-12 gap-4 sm:col-span-4"> <div class="grid grid-cols-2 col-span-12 gap-2 sm:col-span-4">
<!-- Total Rides Card --> <!-- Total Rides Card -->
<a href="{% url 'parks:rides:ride_list' park.slug %}" <a href="{% url 'parks:rides:ride_list' park.slug %}"
class="flex flex-col items-center justify-center p-4 text-center transition-transform bg-white rounded-lg shadow-lg hover:scale-[1.02] dark:bg-gray-800"> class="flex flex-col items-center justify-center p-3 text-center transition-transform bg-white rounded-lg shadow-lg hover:scale-[1.02] dark:bg-gray-800">
<dt class="text-sm font-semibold text-gray-900 sm:text-base lg:text-lg dark:text-white">Total Rides</dt> <dt class="text-sm font-semibold text-gray-900 sm:text-base lg:text-lg dark:text-white">Total Rides</dt>
<dd class="mt-2 text-xl font-bold text-sky-900 hover:text-sky-800 sm:text-2xl lg:text-3xl dark:text-sky-400 dark:hover:text-sky-300"> <dd class="mt-1 text-xl font-bold text-sky-900 hover:text-sky-800 sm:text-2xl lg:text-3xl dark:text-sky-400 dark:hover:text-sky-300">
{{ park.total_rides|default:"N/A" }} {{ park.total_rides|default:"N/A" }}
</dd> </dd>
</a> </a>
<!-- Total Roller Coasters Card --> <!-- Total Roller Coasters Card -->
<div class="flex flex-col items-center justify-center p-4 text-center bg-white rounded-lg shadow-lg dark:bg-gray-800"> <div class="flex flex-col items-center justify-center p-3 text-center bg-white rounded-lg shadow-lg dark:bg-gray-800">
<dt class="text-sm font-semibold text-gray-900 sm:text-base lg:text-lg dark:text-white">Roller Coasters</dt> <dt class="text-sm font-semibold text-gray-900 sm:text-base lg:text-lg dark:text-white">Roller Coasters</dt>
<dd class="mt-2 text-xl font-bold text-sky-900 hover:text-sky-800 sm:text-2xl lg:text-3xl dark:text-sky-400 dark:hover:text-sky-300"> <dd class="mt-1 text-xl font-bold text-sky-900 hover:text-sky-800 sm:text-2xl lg:text-3xl dark:text-sky-400 dark:hover:text-sky-300">
{{ park.total_roller_coasters|default:"N/A" }} {{ park.total_roller_coasters|default:"N/A" }}
</dd> </dd>
</div> </div>
</div> </div>
<!-- Quick Facts Grid --> <!-- Quick Facts Grid -->
<div class="grid h-full grid-cols-3 col-span-12 gap-2 p-4 bg-white rounded-lg shadow-lg sm:col-span-8 dark:bg-gray-800"> <div class="grid h-full grid-cols-3 col-span-12 gap-1 p-3 bg-white rounded-lg shadow-lg sm:col-span-8 dark:bg-gray-800">
{% if park.owner %} {% if park.owner %}
<div class="flex flex-col items-center justify-center p-2 text-center"> <div class="flex flex-col items-center justify-center p-1 text-center">
<i class="text-lg text-blue-600 sm:text-xl lg:text-2xl fas fa-building dark:text-blue-400"></i> <i class="text-lg text-blue-600 sm:text-xl lg:text-2xl fas fa-building dark:text-blue-400"></i>
<dt class="mt-1 text-xs font-medium text-gray-500 sm:text-sm lg:text-base dark:text-gray-400">Owner</dt> <dt class="mt-1 text-xs font-medium text-gray-500 sm:text-sm lg:text-base dark:text-gray-400">Owner</dt>
<dd> <dd>
@@ -102,7 +122,7 @@
{% endif %} {% endif %}
{% if park.opening_date %} {% if park.opening_date %}
<div class="flex flex-col items-center justify-center p-2 text-center"> <div class="flex flex-col items-center justify-center p-1 text-center">
<i class="text-lg text-blue-600 sm:text-xl lg:text-2xl fas fa-calendar-alt dark:text-blue-400"></i> <i class="text-lg text-blue-600 sm:text-xl lg:text-2xl fas fa-calendar-alt dark:text-blue-400"></i>
<dt class="mt-1 text-xs font-medium text-gray-500 sm:text-sm lg:text-base dark:text-gray-400">Opened</dt> <dt class="mt-1 text-xs font-medium text-gray-500 sm:text-sm lg:text-base dark:text-gray-400">Opened</dt>
<dd class="text-xs text-gray-900 sm:text-sm lg:text-base dark:text-white">{{ park.opening_date }}</dd> <dd class="text-xs text-gray-900 sm:text-sm lg:text-base dark:text-white">{{ park.opening_date }}</dd>
@@ -110,7 +130,7 @@
{% endif %} {% endif %}
{% if park.website %} {% if park.website %}
<div class="flex flex-col items-center justify-center p-2 text-center"> <div class="flex flex-col items-center justify-center p-1 text-center">
<i class="text-lg text-blue-600 sm:text-xl lg:text-2xl fas fa-globe dark:text-blue-400"></i> <i class="text-lg text-blue-600 sm:text-xl lg:text-2xl fas fa-globe dark:text-blue-400"></i>
<dt class="mt-1 text-xs font-medium text-gray-500 sm:text-sm lg:text-base dark:text-gray-400">Website</dt> <dt class="mt-1 text-xs font-medium text-gray-500 sm:text-sm lg:text-base dark:text-gray-400">Website</dt>
<dd> <dd>