Compare commits

...

1 Commits

Author SHA1 Message Date
imperosol
fa6e6c320f feat: cache user pictures 2025-09-17 07:47:22 +02:00
3 changed files with 28 additions and 2 deletions

View File

@@ -7,6 +7,7 @@ import {
interface PagePictureConfig { interface PagePictureConfig {
userId: number; userId: number;
lastPhotoDate?: string;
} }
interface Album { interface Album {
@@ -20,11 +21,28 @@ 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 localStorageDateKey = `user${config.userId}PicturesDate`;
const lastCachedDate = localStorage.getItem(localStorageDateKey);
if (
config.lastPhotoDate !== undefined &&
lastCachedDate !== undefined &&
lastCachedDate >= config.lastPhotoDate
) {
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(localStorageDateKey, config.lastPhotoDate);
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 }}, lastPhotoDate: '{{ object.last_photo_date }}' })">
{% 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 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
@@ -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(
last_photo_date=Subquery(
Picture.objects.filter(people__user=OuterRef("id"))
.order_by("-date")
.values("date")[:1]
)
).all()
# Admin views # Admin views