Add feature to download all of your pictures as a user

This commit is contained in:
Antoine Bartuccio 2022-08-07 16:08:56 +02:00
parent c904b2d827
commit 47a332445c
6 changed files with 117 additions and 9 deletions

View File

@ -22,7 +22,7 @@
#
#
from django.urls import re_path, include
from django.urls import re_path, path, include
from api.views import *
from rest_framework import routers
@ -54,4 +54,5 @@ urlpatterns = [
re_path(r"^markdown$", RenderMarkdown, name="api_markdown"),
re_path(r"^mailings$", FetchMailingLists, name="mailings_fetch"),
re_path(r"^uv$", uv_endpoint, name="uv_endpoint"),
path("sas/<int:user>", all_pictures_of_user_endpoint, name="all_pictures_of_user"),
]

View File

@ -78,3 +78,4 @@ from .club import *
from .group import *
from .launderette import *
from .uv import *
from .sas import *

42
api/views/sas.py Normal file
View File

@ -0,0 +1,42 @@
from typing import List
from rest_framework.decorators import api_view, renderer_classes
from rest_framework.exceptions import PermissionDenied
from rest_framework.generics import get_object_or_404
from rest_framework.renderers import JSONRenderer
from rest_framework.request import Request
from rest_framework.response import Response
from core.views import can_edit_prop
from core.models import User
from sas.models import Picture
def all_pictures_of_user(user: User) -> List[Picture]:
return [
relation.picture
for relation in user.pictures.exclude(picture=None)
.order_by("-picture__parent__date", "id")
.select_related("picture__parent")
]
@api_view(["GET"])
@renderer_classes((JSONRenderer,))
def all_pictures_of_user_endpoint(request: Request, user: int):
requested_user: User = get_object_or_404(User, pk=user)
if not can_edit_prop(requested_user, request.user):
raise PermissionDenied
return Response(
[
{
"name": f"{picture.parent.name} - {picture.name}",
"date": picture.date,
"author": str(picture.owner),
"full_size_url": picture.get_download_url(),
"compressed_url": picture.get_download_compressed_url(),
"thumb_url": picture.get_download_thumb_url(),
}
for picture in all_pictures_of_user(requested_user)
]
)

View File

@ -6,6 +6,7 @@
{% block content %}
{% for a in albums %}
<button id="download_all_pictures", onclick=download_pictures()>{% trans %} Download all my pictures {% endtrans %}</button>
<div style="padding: 10px">
<h4>{{ a.name }}</h4>
<hr>
@ -20,3 +21,67 @@
{% endfor %}
{% endblock %}
{% block script %}
{{ super() }}
<script type="text/javascript">
/**
* Download a list of files.
* @author speedplane
*/
function download_files(files) {
function download_next(i) {
if (i >= files.length) {
return;
}
var a = document.createElement('a');
a.href = files[i].download;
a.target = '_parent';
// Use a.download if available, it prevents plugins from opening.
if ('download' in a) {
a.download = files[i].filename;
}
// Add a to the doc for click to work.
(document.body || document.documentElement).appendChild(a);
if (a.click) {
a.click(); // The click method is supported by most browsers.
} else {
$(a).click(); // Backup using jquery
}
// Delete the temporary link.
a.parentNode.removeChild(a);
// Download the next file with a small timeout. The timeout is necessary
// for IE, which will otherwise only download the first file.
setTimeout(function() {
download_next(i + 1);
}, 500);
}
// Initiate the first download.
download_next(0);
}
function download_pictures() {
$("#download_all_pictures").prop("disabled", true);
var xhr = new XMLHttpRequest();
$.ajax({
type: "GET",
url: "{{ url('api:all_pictures_of_user', user=object.id) }}",
tryCount: 0,
xhr: function(){
return xhr;
},
success: function(data){
$("#download_all_pictures").prop("disabled", false);
to_download = [];
data.forEach(picture =>
to_download.push({ download: picture["full_size_url"], filename: picture["name"] })
);
download_files(to_download);
},
error: function(data){
console.log("Error retrieving data from url: " + data);
$("#download_all_pictures").text("{% trans %} Error downloading your pictures {% endtrans %}");
}
});
}
</script>
{% endblock %}

View File

@ -24,6 +24,7 @@
# This file contains all the views that concern the page model
from django.shortcuts import redirect, get_object_or_404
from django.utils.http import http_date
from django.views.generic import ListView, DetailView, TemplateView
from django.views.generic.edit import UpdateView, FormMixin, DeleteView
from django.views.generic.detail import SingleObjectMixin
@ -68,6 +69,7 @@ def send_file(request, file_id, file_class=SithFile, file_attr="file"):
with open(filepath.encode("utf-8"), "rb") as filename:
wrapper = FileWrapper(filename)
response = HttpResponse(wrapper, content_type=f.mime_type)
response["Last-Modified"] = http_date(f.date.timestamp())
response["Content-Length"] = os.path.getsize(filepath.encode("utf-8"))
response["Content-Disposition"] = ('inline; filename="%s"' % f.name).encode(
"utf-8"

View File

@ -48,6 +48,7 @@ from django.views.generic.dates import YearMixin, MonthMixin
from datetime import timedelta, date
import logging
from api.views.sas import all_pictures_of_user
from core.views import (
CanViewMixin,
@ -325,19 +326,15 @@ class UserPicturesView(UserTabsMixin, CanViewMixin, DetailView):
kwargs = super(UserPicturesView, self).get_context_data(**kwargs)
kwargs["albums"] = []
kwargs["pictures"] = {}
picture_qs = (
self.object.pictures.exclude(picture=None)
.order_by("-picture__parent__date", "id")
.select_related("picture__parent")
)
picture_qs = all_pictures_of_user(self.object)
last_album = None
for pict_relation in picture_qs:
album = pict_relation.picture.parent
for picture in picture_qs:
album = picture.parent
if album.id != last_album:
kwargs["albums"].append(album)
kwargs["pictures"][album.id] = []
last_album = album.id
kwargs["pictures"][album.id].append(pict_relation.picture)
kwargs["pictures"][album.id].append(picture)
return kwargs