Allow staff to upload photos has another user.
All checks were successful
Docker / build (release) Successful in 9s

This commit is contained in:
krek0 2026-05-16 19:02:52 +02:00
parent b0027be96c
commit 1de1cb4086
4 changed files with 48 additions and 14 deletions

View file

@ -7,12 +7,15 @@ import datetime
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Div, Layout, Submit
from django import forms
from django.contrib.auth import get_user_model
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
from django_select2.forms import ModelSelect2MultipleWidget
from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget
from .models import Gallery, Tag
User = get_user_model()
class MultipleFileInput(forms.ClearableFileInput):
allow_multiple_selected = True
@ -87,11 +90,27 @@ class UploadForm(forms.Form):
)
def __init__(self, *args, **kwargs):
is_staff = kwargs.pop("is_staff", False)
super().__init__(*args, **kwargs)
if is_staff:
self.fields["owner"] = forms.ModelChoiceField(
User.objects.all(),
label=_("Upload as"),
required=False,
empty_label=_("-- Myself --"),
widget=ModelSelect2Widget(
model=User,
search_fields=["username__icontains", "first_name__icontains", "last_name__icontains"],
attrs={
"data-minimum-input-length": 0,
"data-placeholder": "-- Myself --",
},
),
)
self.helper = FormHelper()
self.helper.include_media = False
self.helper.use_custom_control = False
self.helper.layout = Layout(
layout_fields = [
"file_field",
"gallery",
"new_gallery_title",
@ -102,8 +121,11 @@ class UploadForm(forms.Form):
),
"new_gallery_description",
"new_gallery_tags",
Submit("submit", _("Upload"), css_class="btn btn-success mt-2"),
)
]
if is_staff:
layout_fields.append("owner")
layout_fields.append(Submit("submit", _("Upload"), css_class="btn btn-success mt-2"))
self.helper.layout = Layout(*layout_fields)
def clean(self):
cleaned_data = super().clean()
@ -119,6 +141,9 @@ class UploadForm(forms.Form):
return cleaned_data
def get_owner(self, fallback):
return self.cleaned_data.get("owner") or fallback
def get_or_create_gallery(self):
"""
Get or create gallery

View file

@ -95,11 +95,12 @@ pausebtn.addEventListener('click', () => {
pausebtn.className = pause ? 'btn btn-success' : 'btn btn-warning';
});
async function uploadFile(file, galleryID, csrfvalue) {
async function uploadFile(file, galleryID, csrfvalue, ownerID) {
const sendform = new FormData();
sendform.append('csrfmiddlewaretoken', csrfvalue);
sendform.append('file_field', file);
sendform.append('gallery', galleryID);
if (ownerID) sendform.append('owner', ownerID);
const start = performance.now();
const res = await fetch('/upload/', {
method: 'POST',
@ -146,6 +147,8 @@ ctnbtn.addEventListener('click', async () => {
}
const galleryID = returned.galleryID;
const ownerSelect = document.getElementById('id_owner');
const ownerID = ownerSelect ? ownerSelect.value : null;
uploadInput.disabled = true;
gallerySelect.disabled = true;
@ -194,7 +197,7 @@ ctnbtn.addEventListener('click', async () => {
while (!pause && active < concurrency && queue.length > 0) {
const file = queue.shift();
active++;
uploadFile(file, galleryID, csrfvalue)
uploadFile(file, galleryID, csrfvalue, ownerID)
.catch(e => console.error(e))
.finally(() => { completed++; tuneConcurrency(); active--; updateProgress(); next(); });
}

View file

@ -22,9 +22,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% trans "Drag and drop photos here" %}
</div>
{% crispy form %}
<p class="mt-3">
{% trans "Owner will be" %} <code>{{ request.user.get_full_name }} ({{ request.user.username}})</code>.
</p>
</form>
</div>
</div>

View file

@ -299,15 +299,20 @@ class GalleryUpload(PermissionRequiredMixin, FormView):
success_url = reverse_lazy("photologue:pl-gallery-upload")
permission_required = "photologue.add_gallery"
def _upload_media(self, model, file_field, file_obj, gallery, gallery_dir, post_save=None):
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["is_staff"] = self.request.user.is_staff
return kwargs
def _upload_media(self, model, file_field, file_obj, gallery, gallery_dir, owner, post_save=None):
"""
Create a media object, save it to the DB, schedule file save on commit.
Returns True if uploaded, False if already exists.
"""
title = Path(file_obj.name).stem
if model.objects.filter(title=title, owner=self.request.user, galleries=gallery).exists():
if model.objects.filter(title=title, owner=owner, galleries=gallery).exists():
return False
obj = model(title=title, slug=unique_slug(model, title), owner=self.request.user)
obj = model(title=title, slug=unique_slug(model, title), owner=owner)
file_path = str(gallery_dir / file_obj.name)
with transaction.atomic():
obj.save()
@ -345,6 +350,10 @@ class GalleryUpload(PermissionRequiredMixin, FormView):
gallery_year = Path(str(gallery.date_start.year))
gallery_dir = gallery_year / gallery.slug
owner = form.get_owner(self.request.user)
if owner != self.request.user and not self.request.user.is_staff:
from django.core.exceptions import PermissionDenied
raise PermissionDenied
# Upload pictures and videos
uploaded_photo_name = []
@ -352,9 +361,9 @@ class GalleryUpload(PermissionRequiredMixin, FormView):
files = form.cleaned_data["file_field"]
for photo_file in files:
if is_photo(photo_file):
uploaded = self._upload_media(Photo, "image", photo_file, gallery, gallery_dir)
uploaded = self._upload_media(Photo, "image", photo_file, gallery, gallery_dir, owner)
elif is_video(photo_file):
uploaded = self._upload_media(Video, "file", photo_file, gallery, gallery_dir, post_save=generate_video_thumbnail)
uploaded = self._upload_media(Video, "file", photo_file, gallery, gallery_dir, owner, post_save=generate_video_thumbnail)
else:
messages.error(self.request, f"{photo_file.name} is not a recognized image or video")
jsondata["code"] = 400