diff --git a/photo21/settings.py b/photo21/settings.py index eaa3a790e8a493f529c7f11e2e2c4331eb694d79..0375594a0553aab623585722d11245196505a678 100644 --- a/photo21/settings.py +++ b/photo21/settings.py @@ -42,11 +42,6 @@ ADMINS = [ ("admin", "photos-admin@lists.crans.org"), ] -# Managers receive uploads notification -MANAGERS = [ - ('admin', 'photos-admin@lists.crans.org'), -] - # Use secure cookies in production SESSION_COOKIE_SECURE = not DEBUG CSRF_COOKIE_SECURE = not DEBUG diff --git a/photologue/templates/photologue/gallery_archive.html b/photologue/templates/photologue/gallery_archive.html index 9e58de7be56bb32021c68931feb28391d1455fdf..206dd585ef609e148216ed1045c3a3495d35e44e 100644 --- a/photologue/templates/photologue/gallery_archive.html +++ b/photologue/templates/photologue/gallery_archive.html @@ -9,12 +9,6 @@ SPDX-License-Identifier: GPL-3.0-or-later {% block title %}{% trans "Latest photo galleries" %}{% endblock %} {% block content %} -<div class="row"> - <div class="col-lg-12"> - <h1>{% trans "Latest photo galleries" %}</h1> - </div> -</div> - <div class="row"> <aside class="col-md-2"> <h5>{% trans "Filter by year" %}</h5> @@ -38,4 +32,4 @@ SPDX-License-Identifier: GPL-3.0-or-later {% endif %} </main> </div> -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/photologue/templates/photologue/gallery_archive_year.html b/photologue/templates/photologue/gallery_archive_year.html index 794fd0d564d7a257ffe504b2e93276a915f06541..54cdb9581d50aadc618e4961cba05db795c824c5 100644 --- a/photologue/templates/photologue/gallery_archive_year.html +++ b/photologue/templates/photologue/gallery_archive_year.html @@ -9,27 +9,27 @@ SPDX-License-Identifier: GPL-3.0-or-later {% block title %}{% blocktrans with show_year=year|date:"Y" %}Galleries for {{ show_year }}{% endblocktrans %}{% endblock %} {% block content %} - <div class="row"> - <div class="col-lg-12"> - <h1>{% blocktrans with show_year=year|date:"Y" %}Galleries for {{ show_year }}{% endblocktrans %}</h1> - </div> - </div> - <div class="row"> - <aside class="col-md-2"> - <a href="{% url 'photologue:pl-gallery-archive' %}">⬅ {% trans "View all galleries" %}</a> - </aside> - <main class="col-md-10"> - {% if object_list %} - <div class="row mb-2"> - {% for gallery in object_list %} - <div class="col-6 col-md-3 mb-2"> - {% include "photologue/includes/gallery_sample.html" %} - </div> - {% endfor %} +<div class="row"> + <aside class="col-md-2"> + <h5>{% trans "Filter by year" %}</h5> + <div class="list-group"> + {% for date in date_list %} + <a class="list-group-item list-group-item-action{% if date == year %} active{% endif %}" href="{% url 'photologue:pl-gallery-archive-year' date.year %}">{{ date|date:"Y" }}</a> + {% endfor %} + </div> + </aside> + <main class="col-md-10"> + {% if object_list %} + <div class="row mb-2"> + {% for gallery in object_list %} + <div class="col-6 col-md-3 mb-2"> + {% include "photologue/includes/gallery_sample.html" %} </div> - {% else %} - <p>{% trans "No galleries were found." %}</p> - {% endif %} - </main> - </div> -{% endblock %} \ No newline at end of file + {% endfor %} + </div> + {% else %} + <p>{% trans "No galleries were found." %}</p> + {% endif %} + </main> +</div> +{% endblock %} diff --git a/photologue/views.py b/photologue/views.py index 9bcc837d32ab76e0ef5f523372d86d23f1a9408e..491480482885051ddb90cc88ab5e98b444da0deb 100644 --- a/photologue/views.py +++ b/photologue/views.py @@ -9,7 +9,7 @@ from pathlib import Path from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin -from django.core.mail import mail_managers +from django.core.mail import mail_admins from django.db import IntegrityError from django.http import HttpResponse from django.shortcuts import redirect @@ -27,6 +27,7 @@ from .models import Gallery, Photo, Tag class GalleryDateView(LoginRequiredMixin): model = Gallery date_field = "date_start" + allow_empty = True # Do not 404 if no galleries def get_queryset(self): """Hide galleries with only private photos""" @@ -36,6 +37,12 @@ class GalleryDateView(LoginRequiredMixin): else: return qs.filter(photos__is_public=True).distinct() + def get_context_data(self, **kwargs): + """Always show all years in archive""" + context = super().get_context_data(**kwargs) + context['date_list'] = self.get_queryset().dates(self.date_field, 'year', 'DESC') + return context + class GalleryArchiveIndexView(GalleryDateView, ArchiveIndexView): pass @@ -91,7 +98,7 @@ class PhotoReportView(LoginRequiredMixin, DetailView): url = request.build_absolute_uri(url) # Send mail to managers - mail_managers( + mail_admins( subject=f"Abuse report for photo id {photo.pk}", message=f"{self.request.user.username} reported an abuse for `{photo.title}`: {url}#lg=1&slide={photo.pk}", ) @@ -182,10 +189,15 @@ class GalleryUpload(PermissionRequiredMixin, FormView): # Upload photos # We take files from the request to support multiple upload files = self.request.FILES.getlist("file_field") + + # Get or create gallery gallery = form.get_or_create_gallery() gallery_year = Path(str(gallery.date_start.year)) gallery_dir = gallery_year / gallery.slug - failed_upload = 0 + + # Upload pictures + uploaded_photo_name = [] + already_exists = 0 for photo_file in files: # Check that we have a valid image try: @@ -196,7 +208,6 @@ class GalleryUpload(PermissionRequiredMixin, FormView): messages.error( self.request, f"{photo_file.name} was not recognized as an image" ) - failed_upload += 1 continue title = f"{gallery.title} - {photo_file.name}" @@ -207,32 +218,32 @@ class GalleryUpload(PermissionRequiredMixin, FormView): owner=self.request.user, ) photo_name = str(gallery_dir / photo_file.name) - photo.image.save(photo_name, photo_file) photo.save() photo.galleries.set([gallery]) + + # Save to disk after successful database edit + photo.image.save(photo_name, photo_file) except IntegrityError: - messages.error( - self.request, - f"{photo_file.name} was not uploaded. Maybe the photo was already uploaded.", - ) - failed_upload += 1 + already_exists += 1 + continue + + uploaded_photo_name.append(photo_file.name) # Notify user then managers - if not failed_upload: - messages.success(self.request, "All photos has been successfully uploaded.") + n_success = len(uploaded_photo_name) + if already_exists: + messages.success(self.request, f"{n_success} photo(s) uploaded, {already_exists} photo(s) skipped as they already exist in this gallery.") else: - n_success = len(files) - failed_upload - messages.warning( - self.request, f"Only {n_success} photos were successfully uploaded !" + messages.success(self.request, f"{n_success} photo(s) uploaded.") + + # Notify administrators on new uploads + gallery_url = reverse_lazy("photologue:pl-gallery", args=[gallery.slug]) + gallery_url = self.request.build_absolute_uri(gallery_url) + if uploaded_photo_name: + photos = ", ".join(uploaded_photo_name) + mail_admins( + subject=f"New upload from {self.request.user.username}", + message=f"{self.request.user.username} has uploaded in <{gallery_url}>:\n{photos}", ) - gallery_title = form.cleaned_data["gallery"] or form.cleaned_data.get( - "new_gallery_title", "" - ) - photos = ", ".join(f.name for f in files) - mail_managers( - subject="New photos upload", - message=f"{self.request.user.username} has uploaded in `{gallery_title}`: {photos}", - ) - return super().form_valid(form)