feat: cache user pictures

This commit is contained in:
imperosol
2025-09-17 07:47:22 +02:00
parent 289ffe1109
commit 2a30f30a31
3 changed files with 28 additions and 3 deletions

View File

@@ -7,6 +7,7 @@ import {
interface PagePictureConfig { interface PagePictureConfig {
userId: number; userId: number;
nbPictures?: number;
} }
interface Album { interface Album {
@@ -20,11 +21,27 @@ document.addEventListener("alpine:init", () => {
loading: true, loading: true,
albums: [] as Album[], albums: [] as Album[],
async init() { async fetchPictures(): Promise<PictureSchema[]> {
const localStorageKey = `user${config.userId}Pictures`;
const localStorageInvalidationKey = `user${config.userId}PicturesNumber`;
const lastCachedNumber = localStorage.getItem(localStorageInvalidationKey);
if (
lastCachedNumber !== null &&
Number.parseInt(lastCachedNumber) === config.nbPictures
) {
return JSON.parse(localStorage.getItem(localStorageKey));
}
const pictures = await paginated(picturesFetchPictures, { const pictures = await paginated(picturesFetchPictures, {
// biome-ignore lint/style/useNamingConvention: from python api // biome-ignore lint/style/useNamingConvention: from python api
query: { users_identified: [config.userId] }, query: { users_identified: [config.userId] },
} as PicturesFetchPicturesData); } as PicturesFetchPicturesData);
localStorage.setItem(localStorageInvalidationKey, config.nbPictures.toString());
localStorage.setItem(localStorageKey, JSON.stringify(pictures));
return pictures;
},
async init() {
const pictures = await this.fetchPictures();
const groupedAlbums = Object.groupBy(pictures, (i: PictureSchema) => i.album.id); const groupedAlbums = Object.groupBy(pictures, (i: PictureSchema) => i.album.id);
this.albums = Object.values(groupedAlbums).map((pictures: PictureSchema[]) => { this.albums = Object.values(groupedAlbums).map((pictures: PictureSchema[]) => {
return { return {

View File

@@ -15,7 +15,7 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<main x-data="user_pictures({ userId: {{ object.id }} })"> <main x-data="user_pictures({ userId: {{ object.id }}, nbPictures: {{ object.nb_pictures }} })">
{% if user.id == object.id %} {% if user.id == object.id %}
{{ download_button(_("Download all my pictures")) }} {{ download_button(_("Download all my pictures")) }}
{% endif %} {% endif %}

View File

@@ -16,6 +16,7 @@ from typing import Any
from django.conf import settings from django.conf import settings
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db.models import Count, OuterRef, Subquery
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.urls import reverse from django.urls import reverse
@@ -36,7 +37,7 @@ from sas.forms import (
PictureModerationRequestForm, PictureModerationRequestForm,
PictureUploadForm, PictureUploadForm,
) )
from sas.models import Album, Picture from sas.models import Album, PeoplePictureRelation, Picture
class AlbumCreateFragment(FragmentMixin, CreateView): class AlbumCreateFragment(FragmentMixin, CreateView):
@@ -178,6 +179,13 @@ class UserPicturesView(UserTabsMixin, CanViewMixin, DetailView):
context_object_name = "profile" context_object_name = "profile"
template_name = "sas/user_pictures.jinja" template_name = "sas/user_pictures.jinja"
current_tab = "pictures" current_tab = "pictures"
queryset = User.objects.annotate(
nb_pictures=Subquery(
PeoplePictureRelation.objects.filter(user=OuterRef("id"))
.values("user_id")
.values(count=Count("*"))
)
).all()
# Admin views # Admin views