mirror of
https://github.com/ae-utbm/sith.git
synced 2025-04-04 19:00:27 +00:00
Use Alpine and the API for SAS picture upload
This commit is contained in:
parent
41d33f3e9e
commit
305f37a806
@ -833,8 +833,9 @@ Welcome to the wiki page!
|
||||
size=file.size,
|
||||
)
|
||||
pict.file.name = p.name
|
||||
pict.clean()
|
||||
pict.full_clean()
|
||||
pict.generate_thumbnails()
|
||||
pict.save()
|
||||
|
||||
img_skia = Picture.objects.get(name="skia.jpg")
|
||||
img_sli = Picture.objects.get(name="sli.jpg")
|
||||
|
@ -134,7 +134,6 @@ class Picture(SasFile):
|
||||
self.thumbnail.name = new_extension_name
|
||||
self.compressed = compressed
|
||||
self.compressed.name = new_extension_name
|
||||
self.save()
|
||||
|
||||
def rotate(self, degree):
|
||||
for attr in ["file", "compressed", "thumbnail"]:
|
||||
@ -235,6 +234,8 @@ class Album(SasFile):
|
||||
return Album.objects.filter(parent=self)
|
||||
|
||||
def get_absolute_url(self):
|
||||
if self.id == settings.SITH_SAS_ROOT_DIR_ID:
|
||||
return reverse("sas:main")
|
||||
return reverse("sas:album", kwargs={"album_id": self.id})
|
||||
|
||||
def get_download_url(self):
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
type PicturesFetchPicturesData,
|
||||
albumFetchAlbum,
|
||||
picturesFetchPictures,
|
||||
picturesUploadPicture,
|
||||
} from "#openapi";
|
||||
|
||||
interface AlbumPicturesConfig {
|
||||
@ -78,4 +79,40 @@ document.addEventListener("alpine:init", () => {
|
||||
this.loading = false;
|
||||
},
|
||||
}));
|
||||
|
||||
Alpine.data("pictureUpload", (albumId: number) => ({
|
||||
errors: [] as string[],
|
||||
pictures: [],
|
||||
sending: false,
|
||||
progress: null as HTMLProgressElement,
|
||||
|
||||
init() {
|
||||
this.progress = this.$refs.progress;
|
||||
},
|
||||
|
||||
async sendPictures() {
|
||||
const input = this.$refs.pictures as HTMLInputElement;
|
||||
const files = input.files;
|
||||
this.progress.value = 0;
|
||||
this.progress.max = files.length;
|
||||
this.sending = true;
|
||||
for (const file of files) {
|
||||
await this.sendPicture(file);
|
||||
}
|
||||
this.sending = false;
|
||||
// This should trigger a reload of the pictures of the `picture` Alpine data
|
||||
this.$dispatch("pictures-upload-done");
|
||||
},
|
||||
|
||||
async sendPicture(file: File) {
|
||||
const res = await picturesUploadPicture({
|
||||
// biome-ignore lint/style/useNamingConvention: api is snake_case
|
||||
body: { album_id: albumId, picture: file },
|
||||
});
|
||||
if (!res.response.ok) {
|
||||
this.errors.push(`${file.name} : ${res.error.detail}`);
|
||||
}
|
||||
this.progress.value += 1;
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
@ -73,7 +73,7 @@
|
||||
<div class="text">{% trans %}To be moderated{% endtrans %}</div>
|
||||
</template>
|
||||
</div>
|
||||
{% if edit_mode %}
|
||||
{% if is_sas_admin %}
|
||||
<input type="checkbox" name="file_list" :value="album.id">
|
||||
{% endif %}
|
||||
</a>
|
||||
@ -86,7 +86,7 @@
|
||||
<h4>{% trans %}Pictures{% endtrans %}</h4>
|
||||
<br>
|
||||
{{ download_button(_("Download album")) }}
|
||||
<div class="photos" :aria-busy="loading">
|
||||
<div class="photos" :aria-busy="loading" @pictures-upload-done.window="fetchPictures">
|
||||
<template x-for="picture in getPage(page)">
|
||||
<a :href="picture.sas_url">
|
||||
<div class="photo" :class="{not_moderated: !picture.is_moderated}">
|
||||
@ -141,115 +141,3 @@
|
||||
{{ timezone.now() - start }}
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
{{ super() }}
|
||||
<script>
|
||||
// Todo: migrate to alpine.js if we have some time
|
||||
$("form#upload_form").submit(function (event) {
|
||||
let formData = new FormData($(this)[0]);
|
||||
|
||||
if(!formData.get('album_name') && !formData.get('images').name)
|
||||
return false;
|
||||
|
||||
if(!formData.get('images').name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
let errorList;
|
||||
if((errorList = this.querySelector('#upload_form ul.errorlist.nonfield')) === null) {
|
||||
errorList = document.createElement('ul');
|
||||
errorList.classList.add('errorlist', 'nonfield');
|
||||
this.insertBefore(errorList, this.firstElementChild);
|
||||
}
|
||||
|
||||
while(errorList.childElementCount > 0)
|
||||
errorList.removeChild(errorList.firstElementChild);
|
||||
|
||||
let progress;
|
||||
if((progress = this.querySelector('progress')) === null) {
|
||||
progress = document.createElement('progress');
|
||||
progress.value = 0;
|
||||
let p = document.createElement('p');
|
||||
p.appendChild(progress);
|
||||
this.insertBefore(p, this.lastElementChild);
|
||||
}
|
||||
|
||||
let dataHolder;
|
||||
|
||||
if(formData.get('album_name')) {
|
||||
dataHolder = new FormData();
|
||||
dataHolder.set('csrfmiddlewaretoken', '{{ csrf_token }}');
|
||||
dataHolder.set('album_name', formData.get('album_name'));
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: "{{ url('sas:album_upload', album_id=object.id) }}",
|
||||
data: dataHolder,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: onSuccess
|
||||
});
|
||||
}
|
||||
|
||||
let images = formData.getAll('images');
|
||||
let imagesCount = images.length;
|
||||
let completeCount = 0;
|
||||
|
||||
let poolSize = 1;
|
||||
let imagePool = [];
|
||||
|
||||
while(images.length > 0 && imagePool.length < poolSize) {
|
||||
let image = images.shift();
|
||||
imagePool.push(image);
|
||||
sendImage(image);
|
||||
}
|
||||
|
||||
function sendImage(image) {
|
||||
dataHolder = new FormData();
|
||||
dataHolder.set('csrfmiddlewaretoken', '{{ csrf_token }}');
|
||||
dataHolder.set('images', image);
|
||||
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: "{{ url('sas:album_upload', album_id=object.id) }}",
|
||||
data: dataHolder,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
})
|
||||
.fail(onSuccess.bind(undefined, image))
|
||||
.done(onSuccess.bind(undefined, image))
|
||||
.always(next.bind(undefined, image));
|
||||
}
|
||||
|
||||
function next(image, _, __) {
|
||||
let index = imagePool.indexOf(image);
|
||||
let nextImage = images.shift();
|
||||
|
||||
if(index !== -1)
|
||||
imagePool.splice(index, 1);
|
||||
|
||||
if(nextImage) {
|
||||
imagePool.push(nextImage);
|
||||
sendImage(nextImage);
|
||||
}
|
||||
}
|
||||
|
||||
function onSuccess(image, data, _, __) {
|
||||
let errors = [];
|
||||
|
||||
if ($(data.responseText).find('.errorlist.nonfield')[0])
|
||||
errors = Array.from($(data.responseText).find('.errorlist.nonfield')[0].children);
|
||||
|
||||
while(errors.length > 0)
|
||||
errorList.appendChild(errors.shift());
|
||||
|
||||
progress.value = ++completeCount / imagesCount;
|
||||
if(progress.value === 1 && errorList.children.length === 0)
|
||||
document.location.reload()
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -18,7 +18,6 @@ from django.urls import path
|
||||
from sas.views import (
|
||||
AlbumCreateFragment,
|
||||
AlbumEditView,
|
||||
AlbumUploadView,
|
||||
AlbumView,
|
||||
ModerationView,
|
||||
PictureAskRemovalView,
|
||||
@ -36,9 +35,6 @@ urlpatterns = [
|
||||
path("", SASMainView.as_view(), name="main"),
|
||||
path("moderation/", ModerationView.as_view(), name="moderation"),
|
||||
path("album/<int:album_id>/", AlbumView.as_view(), name="album"),
|
||||
path(
|
||||
"album/<int:album_id>/upload/", AlbumUploadView.as_view(), name="album_upload"
|
||||
),
|
||||
path("album/<int:album_id>/edit/", AlbumEditView.as_view(), name="album_edit"),
|
||||
path("album/<int:album_id>/preview/", send_album, name="album_preview"),
|
||||
path("picture/<int:picture_id>/", PictureView.as_view(), name="picture"),
|
||||
|
41
sas/views.py
41
sas/views.py
@ -16,22 +16,25 @@ from typing import Any
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import DetailView, TemplateView
|
||||
from django.views.generic.edit import FormMixin, FormView, UpdateView
|
||||
from django.urls import reverse
|
||||
from django.utils.safestring import SafeString
|
||||
from django.views.generic import CreateView, DetailView, TemplateView
|
||||
from django.views.generic.edit import FormView, UpdateView
|
||||
|
||||
from core.auth.mixins import CanEditMixin, CanViewMixin
|
||||
from core.models import SithFile, User
|
||||
from core.views import UseFragmentsMixin
|
||||
from core.views.files import FileView, send_file
|
||||
from core.views.mixins import FragmentMixin, FragmentRenderer
|
||||
from core.views.user import UserTabsMixin
|
||||
from sas.forms import (
|
||||
AlbumCreateForm,
|
||||
AlbumEditForm,
|
||||
PictureEditForm,
|
||||
PictureModerationRequestForm,
|
||||
SASForm,
|
||||
PictureUploadForm,
|
||||
)
|
||||
from sas.models import Album, Picture
|
||||
|
||||
@ -116,32 +119,6 @@ def send_thumb(request, picture_id):
|
||||
return send_file(request, picture_id, Picture, "thumbnail")
|
||||
|
||||
|
||||
class AlbumUploadView(CanViewMixin, DetailView, FormMixin):
|
||||
model = Album
|
||||
form_class = SASForm
|
||||
pk_url_kwarg = "album_id"
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
if not self.object.file:
|
||||
self.object.generate_thumbnail()
|
||||
self.form = self.get_form()
|
||||
parent = SithFile.objects.filter(id=self.object.id).first()
|
||||
files = request.FILES.getlist("images")
|
||||
if request.user.is_subscribed and self.form.is_valid():
|
||||
self.form.process(
|
||||
parent=parent,
|
||||
owner=request.user,
|
||||
files=files,
|
||||
automodere=(
|
||||
request.user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID)
|
||||
or request.user.is_root
|
||||
),
|
||||
)
|
||||
if self.form.is_valid():
|
||||
return HttpResponse(str(self.form.errors), status=200)
|
||||
return HttpResponse(str(self.form.errors), status=500)
|
||||
|
||||
class AlbumView(CanViewMixin, UseFragmentsMixin, DetailView):
|
||||
model = Album
|
||||
pk_url_kwarg = "album_id"
|
||||
|
Loading…
x
Reference in New Issue
Block a user