From 11fccaaf06f45a11835f393298c6e6b187d53afb Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:11:45 +0000 Subject: [PATCH] fix location add --- .gitignore | 1 + media/views.py | 16 +++---- parks/__pycache__/views.cpython-312.pyc | Bin 24235 -> 25306 bytes parks/forms.py | 11 ++++- parks/views.py | 36 ++++++++++++---- static/css/tailwind.css | 19 ++++----- templates/parks/park_detail.html | 54 ++++++++++++++++-------- 7 files changed, 91 insertions(+), 46 deletions(-) diff --git a/.gitignore b/.gitignore index 41c92e18..6bbc4c93 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ moderation/__pycache__ rides/__pycache__ ssh_tools.jsonc thrillwiki/__pycache__/settings.cpython-312.pyc +parks/__pycache__/views.cpython-312.pyc diff --git a/media/views.py b/media/views.py index 99a7ec9a..5d6c98f5 100644 --- a/media/views.py +++ b/media/views.py @@ -57,7 +57,7 @@ def upload_photo(request): # Get the object instance 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: return JsonResponse( { @@ -82,17 +82,17 @@ def upload_photo(request): photo = Photo.objects.create( image=request.FILES["image"], content_type=content_type, - object_id=obj.id, + object_id=obj.pk, uploaded_by=request.user, # Add the user who uploaded the photo is_primary=not Photo.objects.filter( - content_type=content_type, object_id=obj.id + content_type=content_type, object_id=obj.pk ).exists(), is_approved=is_approved # Auto-approve if the user is a moderator, admin, or superuser ) return JsonResponse( { - "id": photo.id, + "id": photo.pk, "url": photo.image.url, "caption": photo.caption, "is_primary": photo.is_primary, @@ -113,7 +113,7 @@ def upload_photo(request): def set_primary_photo(request, photo_id): """Set a photo as primary""" 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 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): """Update a photo's caption""" 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 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.save() - return JsonResponse({"id": photo.id, "caption": photo.caption}) + return JsonResponse({"id": photo.pk, "caption": photo.caption}) except Exception as e: 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): """Delete a photo""" 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 if not request.user.has_perm("media.delete_photo"): diff --git a/parks/__pycache__/views.cpython-312.pyc b/parks/__pycache__/views.cpython-312.pyc index c24ba5f6816a4ffca3df63727f9de7a0f6530d96..519db473214b4443381c41341f5634cc510e24b3 100644 GIT binary patch delta 7670 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 delta 6657 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

p~6iO3Rg)IY` zsiwHbWwex1H0KIhUO;#op&fx!A1o$3+7l^icbUDlDM;$rhnq&BMt0t=G*4PO=@-x* z$un>WByp2w>OvLYE!5L900y(b_9d3PrGhlErY*~dkX3|S*QXR%9`r2SpcL;+aSVQX zX3!S~LN6gKNiUF9P=tSi|7tC}xTPq+i-@gcRyNthTI3YBk`$?UoRf;Jtg^L%iB&=8 zu3;HYByuVGC3b)7o+{3hO!HiANh-#y;YzZZ)rVJ*_*7r`Bq@CYm+&;gGq?sMR6MDv zoIcC`eB<&^8-ea`pbh3@!OspSDDVY(e-NtB--3@US$#@4i2)vA%OoevzS4t*bt!sc z^erMN=}+`Rf&xDcp+LD(4CPmxq0}HlDHbAb2%SHihj@)vW)(#qGEY#%K^$5r@nW4? z_Sr^{Nk)!P2Q<#k9&1BxP?G-pS91hk21k&Wec2AxUl>eH*w9eJ5@j}t_GPHNWHn#d zxHTyaHu1{&MW+qhlBuOxqf9@vt0;{pQexz{2ADS+Z~3k<0>eqXD^b0=e0|XdOUyrKB@+ zTdqTQKXy^xs=RqJlXS@bG5C~>J07|lXw4k)7~Hym))da=_-tcdSs>|vQeCuwvdqy9 zu)LWk9x2Q9{FP?<3k5Ta{ycHfZZ+bU%j9xn1nFXBoxYk1gC-dHzFMqHfKxQ@Gk)EouA0n$9r08*1V!}jq7GlYsW{TS;4|0S96 zK^(Ujq-G*bYG4vhY8Ffus#==VSUTEw^rqNJC4|8#3jDmCLisxgyl{UPB`mV@Jcd4x z&F>@Ji|_*hKIcpE52)E#;pvMA=MX-YuE0)9_+!fFr-{l8caeFX=mC=N*hR zhj1E!)0=-q=~aY(L+C)5_$eZf{Wg$vNg0KE9;oUE1}NOr{S0+h6@LF~aBat#&}%qA zK?owej*uchC|yMGAn@wR>nN|=7-A?pgBq+sqb6Qn`KDckb_Q{TDjDVXD7yKOa!eQR zj>bn6P80R)Id&LJj0|b?4fJ#kK+Oi=Rd5bc zqX>9Cl;Yd}7sm81S|hB-RIda9E@Wn$Iqc0X&Wc%!S@i!t%Po3;U%rpP#mw==Eb3i; z)i-m;{bU2XtM3fl@|`OUG0&cDtTErqs&hT8t~!f-W{*$)6SyApV}gQsp%;`BiaJ!I z1>tHYb}(d1-5#m9nq~wZ*{4zB9|%09y0aa|bSAV8d==nw8n3YE0K$g|e-fB|Z!mSo zdy3t#w_N%u#&jI62@Bbgy%o#e36y?y!`Thj0u9rFhHr%~2U^%udshRuePi#o5`4kw zeERum%dXg4>BCXM=##UN12<^Ynp59{xnLKZ3igk8ZYRHB=E$mkB#iWn03T)1e(d6TNl}P8Y=+iN{VY;V$U0_;esdeW5zV>~ zx)DwyJdVH*6L-S%!N-T8L$|dYPRJv1Wi!o#$>E=%zR2ABZ())Bfp9gcn6da~EdCiw v{){DO#*#hj0NrdiQ3<(~T=dmEQ#cFj1bH@Y?l8^kxIEj%zP~?U!O8v?F%{lj diff --git a/parks/forms.py b/parks/forms.py index 869fb3b0..4e627025 100644 --- a/parks/forms.py +++ b/parks/forms.py @@ -1,6 +1,7 @@ from django import forms from decimal import Decimal, InvalidOperation, ROUND_DOWN from .models import Park +from location.models import Location class ParkForm(forms.ModelForm): @@ -207,8 +208,14 @@ class ParkForm(forms.ModelForm): 'postal_code': self.cleaned_data.get('postal_code'), } - # Set location data to be saved with the park - park.set_location(**location_data) + # Handle location: update if exists, create if not + 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: park.save() diff --git a/parks/views.py b/parks/views.py index 987cedda..81fae91f 100644 --- a/parks/views.py +++ b/parks/views.py @@ -17,6 +17,7 @@ from moderation.mixins import EditSubmissionMixin, PhotoSubmissionMixin, History from moderation.models import EditSubmission from media.models import Photo from location.models import Location +from reviews.models import Review # Import the Review model def location_search(request): @@ -145,7 +146,7 @@ class ParkListView(ListView): def get(self, request, *args, **kwargs): # 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 self.template_name = "parks/partials/park_list.html" return super().get(request, *args, **kwargs) @@ -167,7 +168,7 @@ class ParkDetailView( 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] + return Park.get_by_slug(slug)[0] def get_queryset(self): return super().get_queryset().prefetch_related( @@ -186,6 +187,17 @@ class ParkDetailView( '-status', # OPERATING will come before others '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 def get_redirect_url_pattern(self): @@ -214,8 +226,7 @@ class ParkCreateView(LoginRequiredMixin, CreateView): data[field] = str(data[field]) return data - def form_valid(self, form): - # Normalize coordinates before saving + def normalize_coordinates(self, form): if form.cleaned_data.get("latitude"): lat = Decimal(str(form.cleaned_data["latitude"])) 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"])) 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) # Create submission record @@ -236,7 +251,7 @@ class ParkCreateView(LoginRequiredMixin, CreateView): ) # 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: self.object = form.save() submission.object_id = self.object.id @@ -337,8 +352,7 @@ class ParkUpdateView(LoginRequiredMixin, UpdateView): data[field] = str(data[field]) return data - def form_valid(self, form): - # Normalize coordinates before saving + def normalize_coordinates(self, form): if form.cleaned_data.get("latitude"): lat = Decimal(str(form.cleaned_data["latitude"])) 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"])) 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) # Create submission record @@ -360,7 +378,7 @@ class ParkUpdateView(LoginRequiredMixin, UpdateView): ) # 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: self.object = form.save() submission.status = "APPROVED" @@ -464,7 +482,7 @@ class ParkAreaDetailView( 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) + obj, is_old_slug = ParkArea.get_by_slug(area_slug) if obj.park.slug != park_slug: raise self.model.DoesNotExist("Park slug doesn't match") return obj diff --git a/static/css/tailwind.css b/static/css/tailwind.css index e886bbe3..38403b80 100644 --- a/static/css/tailwind.css +++ b/static/css/tailwind.css @@ -2948,6 +2948,10 @@ select { padding: 0.125rem; } +.p-1 { + padding: 0.25rem; +} + .p-1\.5 { padding: 0.375rem; } @@ -3912,6 +3916,11 @@ select { line-height: 1.5rem; } + .sm\:text-lg { + font-size: 1.125rem; + line-height: 1.75rem; + } + .sm\:text-sm { font-size: 0.875rem; line-height: 1.25rem; @@ -3926,11 +3935,6 @@ select { font-size: 0.75rem; line-height: 1rem; } - - .sm\:text-lg { - font-size: 1.125rem; - line-height: 1.75rem; - } } @media (min-width: 768px) { @@ -3972,11 +3976,6 @@ select { line-height: 1; } - .md\:text-xl { - font-size: 1.25rem; - line-height: 1.75rem; - } - .md\:text-lg { font-size: 1.125rem; line-height: 1.75rem; diff --git a/templates/parks/park_detail.html b/templates/parks/park_detail.html index 5510e04c..bac10ddd 100644 --- a/templates/parks/park_detail.html +++ b/templates/parks/park_detail.html @@ -33,22 +33,42 @@ Upload Photo {% endif %} + + + {% if not park.reviews.exists %} + + Add Review + + {% else %} + {% if user.has_reviewed_park(park) %} + + Edit Review + + {% else %} + + Add Review + + {% endif %} + {% endif %} {% endif %} -

+
-
+

{{ park.name }}

{% if park.formatted_location %} -
+

{{ park.formatted_location }}

- {% endif %} -
- + + {{ park.average_rating|floatformat:1 }}/10 @@ -65,31 +85,31 @@
-
+
-
+
+ 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">
Total Rides
-
+
{{ park.total_rides|default:"N/A" }}
-
+
Roller Coasters
-
+
{{ park.total_roller_coasters|default:"N/A" }}
-
+
{% if park.owner %} -
+
Owner
@@ -102,7 +122,7 @@ {% endif %} {% if park.opening_date %} -
+
Opened
{{ park.opening_date }}
@@ -110,7 +130,7 @@ {% endif %} {% if park.website %} -
+
Website