Staff members can inspect private pictures
This commit is contained in:
parent
d7a39a0334
commit
696bc4d5c1
7 changed files with 49 additions and 53 deletions
|
|
@ -52,13 +52,6 @@ else:
|
|||
fn = unicodedata.normalize('NFKD', force_str(filename)).encode('ascii', 'ignore').decode('ascii')
|
||||
return os.path.join('photos', fn)
|
||||
|
||||
# Support CACHEDIR.TAG spec for backups for ignoring cache dir.
|
||||
# See http://www.brynosaurus.com/cachedir/spec.html
|
||||
PHOTOLOGUE_CACHEDIRTAG = os.path.join("photos", "cache", "CACHEDIR.TAG")
|
||||
if not default_storage.exists(PHOTOLOGUE_CACHEDIRTAG):
|
||||
default_storage.save(PHOTOLOGUE_CACHEDIRTAG, ContentFile(
|
||||
b"Signature: 8a477f597d28d172789f06886806bc55"))
|
||||
|
||||
# Exif Orientation values
|
||||
# Value 0thRow 0thColumn
|
||||
# 1 top left
|
||||
|
|
@ -181,22 +174,13 @@ class Gallery(models.Model):
|
|||
def get_absolute_url(self):
|
||||
return reverse('photologue:pl-gallery', args=[self.slug])
|
||||
|
||||
def latest(self, limit=LATEST_LIMIT, public=True):
|
||||
if not limit:
|
||||
limit = self.photo_count()
|
||||
if public:
|
||||
return self.public()[:limit]
|
||||
else:
|
||||
return self.photos[:limit]
|
||||
|
||||
def sample(self, count=None, public=True):
|
||||
def sample(self, public=True):
|
||||
"""Return a sample of photos, ordered at random."""
|
||||
if not count:
|
||||
count = 1
|
||||
count = 1
|
||||
if count > self.photo_count():
|
||||
count = self.photo_count()
|
||||
if public:
|
||||
photo_set = self.public()
|
||||
photo_set = self.photos.filter(is_public=True)
|
||||
else:
|
||||
photo_set = self.photos
|
||||
return random.sample(set(photo_set), count)
|
||||
|
|
@ -204,16 +188,12 @@ class Gallery(models.Model):
|
|||
def photo_count(self, public=True):
|
||||
"""Return a count of all the photos in this gallery."""
|
||||
if public:
|
||||
return self.public().count()
|
||||
return self.photos.filter(is_public=True).count()
|
||||
else:
|
||||
return self.photos.count()
|
||||
|
||||
photo_count.short_description = _('count')
|
||||
|
||||
def public(self):
|
||||
"""Return a queryset of all the public photos in this gallery."""
|
||||
return self.photos.filter(is_public=True)
|
||||
|
||||
|
||||
class ImageModel(models.Model):
|
||||
image = models.ImageField(_('image'),
|
||||
|
|
@ -375,11 +355,6 @@ class ImageModel(models.Model):
|
|||
return
|
||||
# Save the original format
|
||||
im_format = im.format
|
||||
# Apply effect if found
|
||||
if self.effect is not None:
|
||||
im = self.effect.pre_process(im)
|
||||
elif photosize.effect is not None:
|
||||
im = photosize.effect.pre_process(im)
|
||||
# Rotate if found & necessary
|
||||
if 'Image Orientation' in self.exif() and \
|
||||
self.exif().get('Image Orientation').values[0] in IMAGE_EXIF_ORIENTATION_MAP:
|
||||
|
|
@ -388,11 +363,6 @@ class ImageModel(models.Model):
|
|||
# Resize/crop image
|
||||
if (im.size != photosize.size and photosize.size != (0, 0)) or recreate:
|
||||
im = self.resize_image(im, photosize)
|
||||
# Apply effect if found
|
||||
if self.effect is not None:
|
||||
im = self.effect.post_process(im)
|
||||
elif photosize.effect is not None:
|
||||
im = photosize.effect.post_process(im)
|
||||
# Save file
|
||||
im_filename = getattr(self, "get_%s_filename" % photosize.name)()
|
||||
try:
|
||||
|
|
@ -515,10 +485,10 @@ class Photo(ImageModel):
|
|||
return self.title
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# If crop_from or effect property has been changed on existing image,
|
||||
# If crop_from property has been changed on existing image,
|
||||
# update kwargs to force image recreation in parent class
|
||||
current = Photo.objects.get(pk=self.pk) if self.pk else None
|
||||
if current and (current.crop_from != self.crop_from or current.effect != self.effect):
|
||||
if current and (current.crop_from != self.crop_from):
|
||||
kwargs.update(recreate=True)
|
||||
|
||||
if self.slug is None:
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
{% extends "admin/change_list.html" %}
|
||||
{% load i18n %}
|
||||
{# Hide upload as zip #}
|
||||
|
|
@ -39,6 +39,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||
{% endif %}
|
||||
</h1>
|
||||
{% if gallery.date_start %}<p class="text-muted small">{{ gallery.date_start }}{% if gallery.date_end and gallery.date_end != gallery.date_start %} {% trans "to" %} {{ gallery.date_end }}{% endif %}</p>{% endif %}
|
||||
{% if not gallery.is_public %}<p><span class="badge rounded-pill bg-danger">PRIVATE</span></p>{% endif %}
|
||||
{% if gallery.tags.all %}
|
||||
<p class="text-muted">
|
||||
Tags : {% for tag in gallery.tags.all %}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
{% load i18n %}
|
||||
|
||||
<div class="card text-white bg-dark">
|
||||
<div class="card text-white {% if not gallery.is_public %}bg-danger{% else %}bg-dark{% endif %}">
|
||||
{% for photo in gallery.sample %}
|
||||
<img src="{{ photo.get_thumbnail_url }}" class="card-img-top" alt="{{ photo.title }}">
|
||||
{% endfor %}
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ gallery.title }}</h5>
|
||||
{% if gallery.date_start %}<p class="card-text text-muted small mb-0">{{ gallery.date_start }}{% if gallery.date_end and gallery.date_end != gallery.date_start %} - {{ gallery.date_end }}{% endif %}</p>{% endif %}
|
||||
{% if not gallery.is_public %}<p class="card-text small mb-0">(private)</p>{% endif %}
|
||||
<a href="{{ gallery.get_absolute_url }}" class="stretched-link"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
{% comment %}
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% endcomment %}
|
||||
{% load photologue_tags i18n %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{{ object.title }}{% endblock %}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from django.urls import path, re_path
|
||||
|
||||
from .views import (CustomGalleryDetailView, GalleryArchiveIndexView,
|
||||
from .views import (GalleryDetailView, GalleryArchiveIndexView,
|
||||
GalleryDownload, GalleryUpload, GalleryYearArchiveView,
|
||||
PhotoDetailView, TagDetail)
|
||||
|
||||
|
|
@ -9,8 +9,8 @@ urlpatterns = [
|
|||
path('tag/<slug:slug>/', TagDetail.as_view(), name='tag-detail'),
|
||||
path('gallery/', GalleryArchiveIndexView.as_view(), name='pl-gallery-archive'),
|
||||
re_path(r'^gallery/(?P<year>\d{4})/$', GalleryYearArchiveView.as_view(), name='pl-gallery-archive-year'),
|
||||
path('gallery/<slug:slug>/', CustomGalleryDetailView.as_view(), name='pl-gallery'),
|
||||
path('gallery/<slug:slug>/<int:owner>/', CustomGalleryDetailView.as_view(), name='pl-gallery-owner'),
|
||||
path('gallery/<slug:slug>/', GalleryDetailView.as_view(), name='pl-gallery'),
|
||||
path('gallery/<slug:slug>/<int:owner>/', GalleryDetailView.as_view(), name='pl-gallery-owner'),
|
||||
path('gallery/<slug:slug>/download/', GalleryDownload.as_view(), name='pl-gallery-download'),
|
||||
path('photo/<slug:slug>/', PhotoDetailView.as_view(), name='pl-photo'),
|
||||
path('upload/', GalleryUpload.as_view(), name='pl-gallery-upload'),
|
||||
|
|
|
|||
|
|
@ -24,11 +24,19 @@ from .models import Gallery, Photo, Tag
|
|||
|
||||
|
||||
class GalleryDateView(LoginRequiredMixin):
|
||||
queryset = Gallery.objects.filter(is_public=True)
|
||||
model = Gallery
|
||||
date_field = 'date_start'
|
||||
uses_datetime_field = False # Fix related object access
|
||||
allow_empty = True
|
||||
|
||||
def get_queryset(self):
|
||||
"""Non-staff members only see public galleries"""
|
||||
qs = super().get_queryset()
|
||||
if self.request.user.is_staff:
|
||||
return qs
|
||||
else:
|
||||
return qs.filter(is_public=True)
|
||||
|
||||
|
||||
class GalleryArchiveIndexView(GalleryDateView, ArchiveIndexView):
|
||||
pass
|
||||
|
|
@ -39,7 +47,15 @@ class GalleryYearArchiveView(GalleryDateView, YearArchiveView):
|
|||
|
||||
|
||||
class PhotoDetailView(LoginRequiredMixin, DetailView):
|
||||
queryset = Photo.objects.filter(is_public=True)
|
||||
model = Photo
|
||||
|
||||
def get_queryset(self):
|
||||
"""Non-staff members only see public photos"""
|
||||
qs = super().get_queryset()
|
||||
if self.request.user.is_staff:
|
||||
return qs
|
||||
else:
|
||||
return qs.filter(is_public=True)
|
||||
|
||||
|
||||
class TagDetail(LoginRequiredMixin, DetailView):
|
||||
|
|
@ -57,17 +73,28 @@ class TagDetail(LoginRequiredMixin, DetailView):
|
|||
return context
|
||||
|
||||
|
||||
class CustomGalleryDetailView(LoginRequiredMixin, DetailView):
|
||||
class GalleryDetailView(LoginRequiredMixin, DetailView):
|
||||
"""
|
||||
Custom gallery detail view to filter on photo owner
|
||||
Gallery detail view to filter on photo owner
|
||||
"""
|
||||
queryset = Gallery.objects.filter(is_public=True)
|
||||
model = Gallery
|
||||
|
||||
def get_queryset(self):
|
||||
"""Non-staff members only see public galleries"""
|
||||
qs = super().get_queryset()
|
||||
if self.request.user.is_staff:
|
||||
return qs
|
||||
else:
|
||||
return qs.filter(is_public=True)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
# Query with owner to reduce database lag
|
||||
context['photos'] = self.object.public().select_related('owner')
|
||||
# Non-staff members only see public photos
|
||||
if self.request.user.is_staff:
|
||||
context['photos'] = self.object.photos.all()
|
||||
else:
|
||||
context['photos'] = self.object.photos.filter(is_public=True)
|
||||
|
||||
# List owners
|
||||
context['owners'] = []
|
||||
|
|
@ -83,7 +110,7 @@ class CustomGalleryDetailView(LoginRequiredMixin, DetailView):
|
|||
|
||||
|
||||
class GalleryDownload(LoginRequiredMixin, DetailView):
|
||||
model = Gallery
|
||||
queryset = Gallery.objects.filter(is_public=True)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
"""
|
||||
|
|
@ -93,7 +120,7 @@ class GalleryDownload(LoginRequiredMixin, DetailView):
|
|||
gallery = self.get_object()
|
||||
byte_data = BytesIO()
|
||||
zip_file = zipfile.ZipFile(byte_data, "w")
|
||||
for photo in gallery.public():
|
||||
for photo in gallery.photos.filter(is_public=True):
|
||||
filename = os.path.basename(os.path.normpath(photo.image.path))
|
||||
zip_file.write(photo.image.path, filename)
|
||||
zip_file.close()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue