diff --git a/gallery/templates/gallery/photo_detail.html b/gallery/templates/gallery/photo_detail.html index c15bca2..95ca9f8 100644 --- a/gallery/templates/gallery/photo_detail.html +++ b/gallery/templates/gallery/photo_detail.html @@ -81,19 +81,16 @@
Likes
-
{{ photo.likes }}
+
{{ photo.likes }}
Download photo
{{ photo.width }}x{{ photo.height }}
-
- {% csrf_token %} - -
@@ -137,11 +134,46 @@ - - - - - + + + + {% if liked %} + + {% endif %} + {% endblock %} \ No newline at end of file diff --git a/gallery/urls.py b/gallery/urls.py index 042625e..6731ecc 100644 --- a/gallery/urls.py +++ b/gallery/urls.py @@ -13,6 +13,7 @@ urlpatterns = [ path('about/', views.About.as_view(), name='about_url'), path('search/', views.Search.as_view(), name='search_url'), path('photostream/', views.PhotosList.as_view(), name='photos_url'), + path('like//', views.PhotoLike.as_view(), name='photo_like_url'), path('albums//', views.PhotoDetail.as_view(), name='photo_url'), path('albums//', views.AlbumDetail.as_view(), name='album_url'), path('albums/', views.AlbumsList.as_view(), name='albums_url'), diff --git a/gallery/views.py b/gallery/views.py index 4782b13..a815e8b 100644 --- a/gallery/views.py +++ b/gallery/views.py @@ -2,8 +2,10 @@ from django.conf import settings from django.core.cache import cache from django.core.paginator import Paginator from django.db.models import Count, Q, Sum -from django.shortcuts import get_object_or_404, redirect, render +from django.http import JsonResponse +from django.shortcuts import get_object_or_404, redirect from django.urls import reverse +from django.views import View from django.views.generic import DetailView, ListView, TemplateView from .models import Album, Photo, Redir @@ -33,7 +35,7 @@ class AlbumsList(ListView): cache.set(key, queryset, 60 * 5) return queryset - + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) page = int(self.request.GET.get('page', 1)) @@ -43,7 +45,7 @@ class AlbumsList(ListView): if page > 1: canonical_url += f'?page={page}' context['canonical_url'] = canonical_url - + return context @@ -57,7 +59,7 @@ class AlbumDetail(DetailView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - #photos = self.object.photos.all().order_by('taken_at') + # photos = self.object.photos.all().order_by('taken_at') photos = self.object.photos.all().select_related('album').order_by('taken_at') paginator = Paginator(photos, 30) @@ -77,7 +79,6 @@ class AlbumDetail(DetailView): return context - class PhotosList(ListView): """Shows all public photos sorted by user-selected ordering.""" model = Photo @@ -108,7 +109,7 @@ class PhotoDetail(DetailView): def get_object(self, queryset=None): album_slug = self.kwargs.get('album_slug') photo_slug = self.kwargs.get('photo_slug') - #photo = get_object_or_404(Photo, slug=photo_slug, album__slug=album_slug) + # photo = get_object_or_404(Photo, slug=photo_slug, album__slug=album_slug) photo = get_object_or_404(Photo.objects.select_related('album'), slug=photo_slug, album__slug=album_slug) # Track views using session to avoid duplicate counts @@ -124,21 +125,37 @@ class PhotoDetail(DetailView): "next": self.object.get_next(), "prev": self.object.get_prev(), "canonical_url": self.request.build_absolute_uri(self.object.get_absolute_url()), + "liked": self.request.session.get(f"liked_{self.object.slug}", False) }) return context - def post(self, request, *args, **kwargs): - photo = self.get_object() - if request.POST.get("like") == "true" and self.request.session.get(photo.slug) == 0: - photo.add_like() - self.request.session[photo.slug] = 1 +class PhotoLike(View): + """Ajax like photo button.""" + def get(self, request, *args, **kwargs): + return JsonResponse({'error': 'This endpoint only supports POST requests.'}, status=405) + + def post(self, request, album_slug, photo_slug): + photo = get_object_or_404(Photo.objects.select_related('album'), slug=photo_slug, album__slug=album_slug) + session_key = f"liked_{photo.slug}" + liked = request.session.get(session_key, False) + + if not liked: + photo.likes += 1 if request.user.is_authenticated: photo.is_favorite = True - photo.save() + request.session[session_key] = True + status = "liked" + else: + photo.likes = max(0, photo.likes - 1) + if request.user.is_authenticated: + photo.is_favorite = False + request.session[session_key] = False + status = "unliked" - return redirect('gallery:photo_url', album_slug=self.kwargs['album_slug'], photo_slug=self.kwargs['photo_slug']) + photo.save() + return JsonResponse({'success': True, 'likes': photo.likes, 'status': status}) class Search(TemplateView): @@ -175,6 +192,7 @@ class Search(TemplateView): class About(TemplateView): """Static about page.""" template_name = "gallery/about.html" + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['canonical_url'] = self.request.build_absolute_uri(reverse('gallery:about_url'))