From 7598c4762129515bfb6af9b52576f019c35c233e Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 15 Oct 2021 09:20:33 +0200 Subject: [PATCH 01/19] Show owner in photo admin list --- photologue_custom/admin.py | 10 ++++++++++ .../templates/admin/photologue/photo/change_list.html | 3 +++ 2 files changed, 13 insertions(+) create mode 100644 photologue_custom/templates/admin/photologue/photo/change_list.html diff --git a/photologue_custom/admin.py b/photologue_custom/admin.py index 909117d..895d534 100644 --- a/photologue_custom/admin.py +++ b/photologue_custom/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin +from django.utils.translation import gettext_lazy as _ from photologue.admin import GalleryAdmin as GalleryAdminDefault from photologue.admin import PhotoAdmin as PhotoAdminDefault from photologue.models import Gallery, Photo, PhotoEffect, PhotoSize, Watermark @@ -32,7 +33,16 @@ class PhotoAdmin(PhotoAdminDefault): model. """ inlines = [PhotoExtendedInline, ] + list_display = ('title', 'date_taken', 'date_added', + 'is_public', 'view_count', 'admin_thumbnail', 'get_owner') + list_filter = ['date_added', 'is_public', 'extended__owner'] + def get_owner(self, obj): + if not hasattr(obj, 'extended'): + return "No owner" + return obj.extended.owner.username + get_owner.admin_order_field = 'owner' + get_owner.short_description = _('owner') admin.site.unregister(Gallery) admin.site.unregister(Photo) diff --git a/photologue_custom/templates/admin/photologue/photo/change_list.html b/photologue_custom/templates/admin/photologue/photo/change_list.html new file mode 100644 index 0000000..22a98d1 --- /dev/null +++ b/photologue_custom/templates/admin/photologue/photo/change_list.html @@ -0,0 +1,3 @@ +{% extends "admin/change_list.html" %} +{% load i18n %} +{# Hide upload as zip #} \ No newline at end of file From 2200b0d4369389f327c937696f5743fca9d979cc Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 15 Oct 2021 09:21:01 +0200 Subject: [PATCH 02/19] Reduce gallery load time by prefetching owners --- photologue_custom/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/photologue_custom/views.py b/photologue_custom/views.py index 509f6b8..c12d0a1 100644 --- a/photologue_custom/views.py +++ b/photologue_custom/views.py @@ -51,7 +51,9 @@ class CustomGalleryDetailView(DetailView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['photos'] = self.object.public() + + # Query with extended and owner to reduce database lag + context['photos'] = self.object.public().select_related('extended__owner') # List owners context['owners'] = [] From d95f29c870f1c257386258f5606ddd03433c2770 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 15 Oct 2021 09:21:14 +0200 Subject: [PATCH 03/19] Do not crash on missing owner --- photologue_custom/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/photologue_custom/views.py b/photologue_custom/views.py index c12d0a1..49301ff 100644 --- a/photologue_custom/views.py +++ b/photologue_custom/views.py @@ -58,7 +58,7 @@ class CustomGalleryDetailView(DetailView): # List owners context['owners'] = [] for photo in context['photos']: - if photo.extended.owner not in context['owners']: + if hasattr(photo, 'extended') and photo.extended.owner not in context['owners']: context['owners'].append(photo.extended.owner) # Filter on owner From 036cca0f596c920f8d2f09adb9890bfccae68163 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 15 Oct 2021 09:28:37 +0200 Subject: [PATCH 04/19] Order galleries by start date on tag detail pages --- photologue_custom/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/photologue_custom/views.py b/photologue_custom/views.py index 49301ff..33b2426 100644 --- a/photologue_custom/views.py +++ b/photologue_custom/views.py @@ -23,7 +23,8 @@ class TagDetail(LoginRequiredMixin, DetailView): current_tag = self.get_object().slug context = super().get_context_data(**kwargs) context['galleries'] = Gallery.objects.on_site().is_public() \ - .filter(extended__tags__slug=current_tag) + .filter(extended__tags__slug=current_tag) \ + .order_by('-extended__date_start') return context From 1f9d21f290f6a4a30172ff40762c87a3719e1a10 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 15 Oct 2021 09:34:40 +0200 Subject: [PATCH 05/19] Use grid to display galleries --- .../templates/photologue/gallery_detail.html | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/photologue_custom/templates/photologue/gallery_detail.html b/photologue_custom/templates/photologue/gallery_detail.html index f9f0819..2000729 100644 --- a/photologue_custom/templates/photologue/gallery_detail.html +++ b/photologue_custom/templates/photologue/gallery_detail.html @@ -61,14 +61,12 @@ {% endfor %} -
-
- {% for photo in photos %} - - {{ photo.title }}{% if photo.date_taken %} - {{ photo.date_taken|date }} {{ photo.date_taken|time }}{% endif %} - {{ photo.extended.owner.get_full_name }} - - {% endfor %} -
+
+ {% for photo in photos %} + + {{ photo.title }}{% if photo.date_taken %} - {{ photo.date_taken|date }} {{ photo.date_taken|time }}{% endif %} - {{ photo.extended.owner.get_full_name }} + + {% endfor %}
-
+
{% if user.emailaddress_set.all %}

{% trans 'The following e-mail addresses are associated with your account:' %}

diff --git a/photologue_custom/admin.py b/photologue_custom/admin.py index 895d534..41b967f 100644 --- a/photologue_custom/admin.py +++ b/photologue_custom/admin.py @@ -41,9 +41,10 @@ class PhotoAdmin(PhotoAdminDefault): if not hasattr(obj, 'extended'): return "No owner" return obj.extended.owner.username - get_owner.admin_order_field = 'owner' + get_owner.admin_order_field = 'owner' get_owner.short_description = _('owner') + admin.site.unregister(Gallery) admin.site.unregister(Photo) admin.site.unregister(PhotoEffect) From fb99407d1f395a9a825033ef601070847bd543e3 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 15 Oct 2021 09:53:21 +0200 Subject: [PATCH 08/19] Add license header in templates --- photologue_custom/templates/photologue/gallery_archive.html | 3 +++ .../templates/photologue/gallery_archive_year.html | 3 +++ photologue_custom/templates/photologue/gallery_detail.html | 3 +++ photologue_custom/templates/photologue/photo_detail.html | 3 +++ 4 files changed, 12 insertions(+) diff --git a/photologue_custom/templates/photologue/gallery_archive.html b/photologue_custom/templates/photologue/gallery_archive.html index c3571cb..364ae4e 100644 --- a/photologue_custom/templates/photologue/gallery_archive.html +++ b/photologue_custom/templates/photologue/gallery_archive.html @@ -1,4 +1,7 @@ {% extends "photologue/root.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} {% load i18n %} {% block title %}{% trans "Latest photo galleries" %}{% endblock %} diff --git a/photologue_custom/templates/photologue/gallery_archive_year.html b/photologue_custom/templates/photologue/gallery_archive_year.html index 44b1e3c..6a895bb 100644 --- a/photologue_custom/templates/photologue/gallery_archive_year.html +++ b/photologue_custom/templates/photologue/gallery_archive_year.html @@ -1,4 +1,7 @@ {% extends "photologue/root.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} {% load i18n %} {% block title %}{% blocktrans with show_year=year|date:"Y" %}Galleries for {{ show_year }}{% endblocktrans %}{% endblock %} diff --git a/photologue_custom/templates/photologue/gallery_detail.html b/photologue_custom/templates/photologue/gallery_detail.html index 2000729..1a24121 100644 --- a/photologue_custom/templates/photologue/gallery_detail.html +++ b/photologue_custom/templates/photologue/gallery_detail.html @@ -1,4 +1,7 @@ {% extends "photologue/root.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} {% load static i18n %} {% block title %}{{ gallery.title }}{% endblock %} diff --git a/photologue_custom/templates/photologue/photo_detail.html b/photologue_custom/templates/photologue/photo_detail.html index af7ebe8..9aff5b9 100644 --- a/photologue_custom/templates/photologue/photo_detail.html +++ b/photologue_custom/templates/photologue/photo_detail.html @@ -1,4 +1,7 @@ {% extends "photologue/root.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} {% load photologue_tags i18n %} {% block title %}{{ object.title }}{% endblock %} From 2bd96a4380283a6de04f15baa4cec257eaabb9f9 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 15 Oct 2021 10:50:57 +0200 Subject: [PATCH 09/19] Define server admins and moderators --- photo21/settings.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/photo21/settings.py b/photo21/settings.py index 08250a8..b6967f2 100644 --- a/photo21/settings.py +++ b/photo21/settings.py @@ -35,6 +35,16 @@ ALLOWED_HOSTS = [ "photos-dev.crans.org", ] +# Admins receive server errors, this is useful to be notified of potential bugs +ADMINS = [ + ('erdnaxe', 'a+photo21@crans.org'), +] + +# Managers receive notifications about new photos upload +MANAGERS = [ + ('moderation', 'photos@crans.org'), +] + # Application definition From 583a1ffce8200f4243c580d41f5c93f2dd0f0e4f Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 15 Oct 2021 10:51:20 +0200 Subject: [PATCH 10/19] Simplify logic on index page --- photo21/templates/index.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/photo21/templates/index.html b/photo21/templates/index.html index 63be33d..e9fd5fa 100644 --- a/photo21/templates/index.html +++ b/photo21/templates/index.html @@ -46,9 +46,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
- {% if request.user.is_authenticated %} - {% trans "Connected as" %} {{ request.user.username }}. - {% endif %} + {% trans "Connected as" %} {{ request.user.username }}.
{% csrf_token %} Changer la langue : From 727387566db537a9afec3495eafaa6b2b49871b0 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 15 Oct 2021 10:55:07 +0200 Subject: [PATCH 11/19] Add upload page --- photo21/locale/fr/LC_MESSAGES/django.po | 87 ++++++++++++------- photologue_custom/forms.py | 22 +++++ .../templates/photologue/upload.html | 69 +++++++++++++++ photologue_custom/urls.py | 7 +- photologue_custom/views.py | 33 ++++++- 5 files changed, 185 insertions(+), 33 deletions(-) create mode 100644 photologue_custom/forms.py create mode 100644 photologue_custom/templates/photologue/upload.html diff --git a/photo21/locale/fr/LC_MESSAGES/django.po b/photo21/locale/fr/LC_MESSAGES/django.po index 6ea60a9..d0965ce 100644 --- a/photo21/locale/fr/LC_MESSAGES/django.po +++ b/photo21/locale/fr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-13 13:52+0000\n" +"POT-Creation-Date: 2021-10-15 08:52+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -42,19 +42,19 @@ msgstr "" msgid "hash" msgstr "" -#: photo21/settings.py:153 +#: photo21/settings.py:163 msgid "German" msgstr "" -#: photo21/settings.py:154 +#: photo21/settings.py:164 msgid "English" msgstr "" -#: photo21/settings.py:155 +#: photo21/settings.py:165 msgid "Spanish" msgstr "" -#: photo21/settings.py:156 +#: photo21/settings.py:166 msgid "French" msgstr "" @@ -108,7 +108,7 @@ msgstr "" msgid "E-mail Addresses" msgstr "" -#: photo21/templates/account/email.html:9 photo21/templates/base.html:51 +#: photo21/templates/account/email.html:9 photo21/templates/base.html:58 #: photo21/templates/socialaccount/connections.html:9 msgid "Account" msgstr "Compte" @@ -225,27 +225,34 @@ msgstr "" msgid "The ENS Paris-Saclay pictures server." msgstr "" -#: photo21/templates/base.html:35 +#: photo21/templates/base.html:36 msgid "Galleries" msgstr "Galeries" -#: photo21/templates/base.html:39 +#: photo21/templates/base.html:41 +#: photologue_custom/templates/photologue/upload.html:6 +#: photologue_custom/templates/photologue/upload.html:54 +#: photologue_custom/templates/photologue/upload.html:65 +msgid "Upload" +msgstr "Téléversement" + +#: photo21/templates/base.html:46 msgid "Manage" msgstr "Gestion" -#: photo21/templates/base.html:60 +#: photo21/templates/base.html:67 msgid "Log out" msgstr "" -#: photo21/templates/base.html:70 +#: photo21/templates/base.html:77 msgid "Log in" msgstr "" -#: photo21/templates/base.html:79 +#: photo21/templates/base.html:86 msgid "Sign up" msgstr "Inscription" -#: photo21/templates/index.html:50 +#: photo21/templates/index.html:49 msgid "Connected as" msgstr "Connecté en tant que" @@ -268,6 +275,24 @@ msgstr "" msgid "Add a 3rd Party Account" msgstr "" +#: photologue_custom/admin.py:45 photologue_custom/models.py:51 +msgid "owner" +msgstr "propriétaire" + +#: photologue_custom/forms.py:13 +msgid "Gallery" +msgstr "Galerie" + +#: photologue_custom/forms.py:15 +msgid "" +"Select a gallery to add these images to. Leave this empty to create a new " +"gallery from the supplied title." +msgstr "" + +#: photologue_custom/forms.py:19 +msgid "New gallery title" +msgstr "Titre de la nouvelle galerie" + #: photologue_custom/models.py:23 msgid "start date" msgstr "date de début" @@ -276,53 +301,57 @@ msgstr "date de début" msgid "end date" msgstr "date de fin" -#: photologue_custom/models.py:51 -msgid "owner" -msgstr "propriétaire" - -#: photologue_custom/templates/photologue/gallery_archive.html:4 -#: photologue_custom/templates/photologue/gallery_archive.html:9 +#: photologue_custom/templates/photologue/gallery_archive.html:7 +#: photologue_custom/templates/photologue/gallery_archive.html:12 msgid "Latest photo galleries" msgstr "" -#: photologue_custom/templates/photologue/gallery_archive.html:15 +#: photologue_custom/templates/photologue/gallery_archive.html:18 msgid "Filter by year" msgstr "" -#: photologue_custom/templates/photologue/gallery_archive.html:32 +#: photologue_custom/templates/photologue/gallery_archive.html:35 msgid "No galleries were found" msgstr "" -#: photologue_custom/templates/photologue/gallery_archive_year.html:4 -#: photologue_custom/templates/photologue/gallery_archive_year.html:9 +#: photologue_custom/templates/photologue/gallery_archive_year.html:7 +#: photologue_custom/templates/photologue/gallery_archive_year.html:12 #, python-format msgid "Galleries for %(show_year)s" msgstr "" -#: photologue_custom/templates/photologue/gallery_archive_year.html:14 +#: photologue_custom/templates/photologue/gallery_archive_year.html:17 msgid "View all galleries" msgstr "" -#: photologue_custom/templates/photologue/gallery_archive_year.html:26 +#: photologue_custom/templates/photologue/gallery_archive_year.html:29 msgid "No galleries were found." msgstr "" -#: photologue_custom/templates/photologue/gallery_detail.html:35 +#: photologue_custom/templates/photologue/gallery_detail.html:38 msgid "to" msgstr "au" -#: photologue_custom/templates/photologue/gallery_detail.html:49 +#: photologue_custom/templates/photologue/gallery_detail.html:54 msgid "All pictures" msgstr "Toutes les photos" -#: photologue_custom/templates/photologue/gallery_detail.html:63 +#: photologue_custom/templates/photologue/gallery_detail.html:75 msgid "Download all gallery" msgstr "Télécharger toute la galerie" -#: photologue_custom/templates/photologue/photo_detail.html:10 +#: photologue_custom/templates/photologue/photo_detail.html:13 msgid "Published" msgstr "" -#: photologue_custom/templates/photologue/photo_detail.html:22 +#: photologue_custom/templates/photologue/photo_detail.html:25 msgid "This photo is found in the following galleries" msgstr "" + +#: photologue_custom/templates/photologue/upload.html:59 +msgid "Drag and drop photos here" +msgstr "Glissez et déposez les photos ici" + +#: photologue_custom/templates/photologue/upload.html:63 +msgid "Owner will be" +msgstr "Le propriétaire sera" diff --git a/photologue_custom/forms.py b/photologue_custom/forms.py new file mode 100644 index 0000000..5db968f --- /dev/null +++ b/photologue_custom/forms.py @@ -0,0 +1,22 @@ +from django import forms +from django.utils.translation import gettext_lazy as _ +from photologue.models import Gallery + + +class UploadForm(forms.Form): + file_field = forms.FileField( + label="", + widget=forms.ClearableFileInput(attrs={'multiple': True}), + ) + gallery = forms.ModelChoiceField( + Gallery.objects.all(), + label=_('Gallery'), + required=False, + help_text=_('Select a gallery to add these images to. Leave this empty to ' + 'create a new gallery from the supplied title.') + ) + new_gallery_title = forms.CharField( + label=_('New gallery title'), + max_length=250, + required=False, + ) diff --git a/photologue_custom/templates/photologue/upload.html b/photologue_custom/templates/photologue/upload.html new file mode 100644 index 0000000..4e16371 --- /dev/null +++ b/photologue_custom/templates/photologue/upload.html @@ -0,0 +1,69 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n crispy_forms_tags %} +{% block title %}{% trans "Upload" %}{% endblock %} + +{% block extracss %} + +{% endblock %} + +{% block extrajs %} + +{% endblock %} + +{% block content %} +

{% trans "Upload" %}

+
+
+ {% csrf_token %} +
+ {% trans "Drag and drop photos here" %} +
+ {{ form|crispy }} +

+ {% trans "Owner will be" %} {{ request.user.get_full_name }} ({{ request.user.username}}). +

+ + +
+
+{% endblock %} diff --git a/photologue_custom/urls.py b/photologue_custom/urls.py index 6ada0f6..c5fbc20 100644 --- a/photologue_custom/urls.py +++ b/photologue_custom/urls.py @@ -1,8 +1,8 @@ from django.urls import path, re_path -from .views import (CustomGalleryArchiveIndexView, - CustomGalleryYearArchiveView, CustomGalleryDetailView, - GalleryDownload, TagDetail) +from .views import (CustomGalleryArchiveIndexView, CustomGalleryDetailView, + CustomGalleryYearArchiveView, GalleryDownload, + GalleryUpload, TagDetail) urlpatterns = [ path('tag//', TagDetail.as_view(), name='tag-detail'), @@ -11,4 +11,5 @@ urlpatterns = [ path('gallery//', CustomGalleryDetailView.as_view(), name='pl-gallery'), path('gallery///', CustomGalleryDetailView.as_view(), name='pl-gallery-owner'), path('gallery//download/', GalleryDownload.as_view(), name='gallery-download'), + path('upload/', GalleryUpload.as_view(), name='gallery-upload'), ] diff --git a/photologue_custom/views.py b/photologue_custom/views.py index 33b2426..4332f77 100644 --- a/photologue_custom/views.py +++ b/photologue_custom/views.py @@ -6,12 +6,16 @@ import zipfile from io import BytesIO from django.contrib.auth.mixins import LoginRequiredMixin +from django.core.mail import mail_managers from django.http import HttpResponse -from django.views.generic import DetailView +from django.views.generic.detail import DetailView +from django.views.generic.edit import FormView from photologue.models import Gallery from photologue.views import GalleryArchiveIndexView, GalleryYearArchiveView from taggit.models import Tag +from .forms import UploadForm + class TagDetail(LoginRequiredMixin, DetailView): model = Tag @@ -89,3 +93,30 @@ class GalleryDownload(LoginRequiredMixin, DetailView): response = HttpResponse(byte_data.getvalue(), content_type='application/x-zip-compressed') response['Content-Disposition'] = f"attachment; filename={gallery.slug}.zip" return response + + +class GalleryUpload(FormView): + form_class = UploadForm + template_name = "photologue/upload.html" + # success_url = '...' # Replace with your URL or reverse(). + + def post(self, request, *args, **kwargs): + form_class = self.get_form_class() + form = self.get_form(form_class) + files = request.FILES.getlist('file_field') + if form.is_valid(): + for f in files: + print("upload", f) + return self.form_valid(form) + else: + return self.form_invalid(form) + + def form_valid(self, form): + """ + Notify moderators about successful upload + """ + mail_managers( + subject="New upload", + message="", # TODO: put username, gallery and photo names + ) + return super().form_valid(form) From d2fa5ce02f40a62a526ff1df741318a3121a1c6a Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Fri, 15 Oct 2021 12:43:17 +0200 Subject: [PATCH 12/19] Check upload form --- photo21/settings.py | 1 + photo21/templates/base.html | 12 +++++-- photologue_custom/forms.py | 26 +++++++++++++- .../templates/photologue/upload.html | 2 +- photologue_custom/views.py | 35 ++++++++++--------- 5 files changed, 54 insertions(+), 22 deletions(-) diff --git a/photo21/settings.py b/photo21/settings.py index b6967f2..5128667 100644 --- a/photo21/settings.py +++ b/photo21/settings.py @@ -203,6 +203,7 @@ EMAIL_HOST_PASSWORD = os.getenv('EMAIL_PASSWORD', None) # Mail will be sent from this address SERVER_EMAIL = "photos@crans.org" DEFAULT_FROM_EMAIL = f"Serveur photos <{SERVER_EMAIL}>" +EMAIL_SUBJECT_PREFIX = '[Serveur photos] ' # After login redirect user to transfer page LOGIN_REDIRECT_URL = '/' diff --git a/photo21/templates/base.html b/photo21/templates/base.html index a2d1633..44af685 100644 --- a/photo21/templates/base.html +++ b/photo21/templates/base.html @@ -35,10 +35,16 @@ SPDX-License-Identifier: GPL-3.0-or-later {% url 'photologue:pl-gallery-archive' as url %} {% trans 'Galleries' %} + {% if perms.photologue.add_gallery %} + + {% endif %} {% if request.user.is_staff %} - + {% endif %}