change cache on picture download

This commit is contained in:
thomas girod 2024-08-06 13:23:34 +02:00
parent 4506440a62
commit d3b203a4a1
4 changed files with 65 additions and 15 deletions

View File

@ -982,7 +982,7 @@ class SithFile(models.Model):
return True return True
if self.is_in_sas and user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID): if self.is_in_sas and user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID):
return True return True
return user.id == self.owner.id return user.id == self.owner_id
def can_be_viewed_by(self, user): def can_be_viewed_by(self, user):
if hasattr(self, "profile_of"): if hasattr(self, "profile_of"):

View File

@ -45,12 +45,13 @@ class PicturesController(ControllerBase):
# User can view any moderated picture if he/she is subscribed. # User can view any moderated picture if he/she is subscribed.
# If not, he/she can view only the one he/she has been identified on # If not, he/she can view only the one he/she has been identified on
raise PermissionDenied raise PermissionDenied
return ( pictures = list(
filters.filter(Picture.objects.viewable_by(user)) filters.filter(Picture.objects.viewable_by(user))
.distinct() .distinct()
.order_by("-parent__date", "date") .order_by("-parent__date", "date")
.annotate(album=F("parent__name")) .annotate(album=F("parent__name"))
) )
return pictures
@api_controller("/sas/relation", tags="User identification on SAS pictures") @api_controller("/sas/relation", tags="User identification on SAS pictures")

View File

@ -13,8 +13,9 @@
# #
# #
from __future__ import annotations
from io import BytesIO from io import BytesIO
from typing import Self
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
@ -29,7 +30,7 @@ from core.utils import exif_auto_rotate, resize_image
class PictureQuerySet(models.QuerySet): class PictureQuerySet(models.QuerySet):
def viewable_by(self, user: User) -> Self: def viewable_by(self, user: User) -> PictureQuerySet:
"""Filter the pictures that this user can view. """Filter the pictures that this user can view.
Warnings: Warnings:
@ -39,7 +40,7 @@ class PictureQuerySet(models.QuerySet):
return self.all() return self.all()
if user.was_subscribed: if user.was_subscribed:
return self.filter(is_moderated=True) return self.filter(is_moderated=True)
return self.filter(people__user_id=user.id) return self.filter(people__user_id=user.id, is_moderated=True)
class SASPictureManager(models.Manager): class SASPictureManager(models.Manager):
@ -76,19 +77,19 @@ class Picture(SithFile):
return perm return perm
def can_be_viewed_by(self, user: User) -> bool: def can_be_viewed_by(self, user: User) -> bool:
# SAS pictures are visible to old subscribers
# Result is cached 4s for this user
if user.is_anonymous: if user.is_anonymous:
return False return False
perm = cache.get("%d_can_view_pictures" % (user.id), False) cache_key = f"sas:pictures_viewable_by_{user.id}_in_{self.parent_id}"
if not perm: viewable: list[int] | None = cache.get(cache_key)
perm = user.was_subscribed if viewable is None:
viewable = list(
cache.set("%d_can_view_pictures" % (user.id), perm, timeout=4) Picture.objects.filter(parent_id=self.parent_id)
return (perm and self.is_moderated and self.is_in_sas) or self.can_be_edited_by( .viewable_by(user)
user .values_list("pk", flat=True)
) )
cache.set(cache_key, viewable, timeout=10)
return self.id in viewable
def get_download_url(self): def get_download_url(self):
return reverse("sas:download", kwargs={"picture_id": self.id}) return reverse("sas:download", kwargs={"picture_id": self.id})

48
sas/tests/test_model.py Normal file
View File

@ -0,0 +1,48 @@
from django.test import TestCase
from model_bakery import baker, seq
from core.baker_recipes import old_subscriber_user, subscriber_user
from core.models import User
from sas.models import Picture
class TestPictureQuerySet(TestCase):
@classmethod
def setUpTestData(cls):
Picture.objects.all().delete()
cls.pictures = baker.make(
Picture,
is_moderated=True,
is_in_sas=True,
is_folder=False,
name=seq(""),
_quantity=10,
_bulk_create=True,
)
Picture.objects.filter(pk=cls.pictures[0].id).update(is_moderated=False)
def test_root(self):
root = baker.make(User, is_superuser=True)
pictures = list(Picture.objects.viewable_by(root))
self.assertCountEqual(pictures, self.pictures)
def test_subscriber(self):
subscriber = subscriber_user.make()
old_subcriber = old_subscriber_user.make()
for user in (subscriber, old_subcriber):
pictures = list(Picture.objects.viewable_by(user))
self.assertCountEqual(pictures, self.pictures[1:])
def test_not_subscribed_identified(self):
user = baker.make(
# This is the guy who asked the feature of making pictures
# available for tagged users, even if not subscribed
User,
first_name="Pierrick",
last_name="Dheilly",
nick_name="Sahmer",
)
user.pictures.create(picture=self.pictures[0])
user.pictures.create(picture=self.pictures[1])
pictures = list(Picture.objects.viewable_by(user))
assert pictures == [self.pictures[1]]