From 4506440a62870094f700fb9c1dccb876e6c214bb Mon Sep 17 00:00:00 2001 From: thomas girod Date: Tue, 6 Aug 2024 12:37:50 +0200 Subject: [PATCH] add `PictureQuerySet.viewable_by(user)` method --- sas/api.py | 6 ++---- sas/models.py | 23 ++++++++++++++++++++--- sas/tests/test_api.py | 3 ++- sas/views.py | 5 +---- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/sas/api.py b/sas/api.py index 170894d1..f4b98fc3 100644 --- a/sas/api.py +++ b/sas/api.py @@ -41,14 +41,12 @@ class PicturesController(ControllerBase): cf. https://ae.utbm.fr/user/32663/pictures/) """ user: User = self.context.request.user - if not user.is_subscribed and filters.users_identified != {user.id}: + if not user.was_subscribed and filters.users_identified != {user.id}: # 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 raise PermissionDenied return ( - filters.filter( - Picture.objects.filter(is_moderated=True, asked_for_removal=False) - ) + filters.filter(Picture.objects.viewable_by(user)) .distinct() .order_by("-parent__date", "date") .annotate(album=F("parent__name")) diff --git a/sas/models.py b/sas/models.py index 7330d823..c93e0a0d 100644 --- a/sas/models.py +++ b/sas/models.py @@ -14,6 +14,7 @@ # from io import BytesIO +from typing import Self from django.conf import settings from django.core.cache import cache @@ -27,9 +28,25 @@ from core.models import SithFile, User from core.utils import exif_auto_rotate, resize_image +class PictureQuerySet(models.QuerySet): + def viewable_by(self, user: User) -> Self: + """Filter the pictures that this user can view. + + Warnings: + Calling this queryset method may add several additional requests. + """ + if user.is_root or user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID): + return self.all() + if user.was_subscribed: + return self.filter(is_moderated=True) + return self.filter(people__user_id=user.id) + + class SASPictureManager(models.Manager): def get_queryset(self): - return super().get_queryset().filter(is_in_sas=True, is_folder=False) + return PictureQuerySet(self.model, using=self._db).filter( + is_in_sas=True, is_folder=False + ) class SASAlbumManager(models.Manager): @@ -41,7 +58,7 @@ class Picture(SithFile): class Meta: proxy = True - objects = SASPictureManager() + objects = SASPictureManager.from_queryset(PictureQuerySet)() @property def is_vertical(self): @@ -58,7 +75,7 @@ class Picture(SithFile): cache.set("%d_can_edit_pictures" % (user.id), perm, timeout=4) return perm - def can_be_viewed_by(self, user): + 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: diff --git a/sas/tests/test_api.py b/sas/tests/test_api.py index a9cb80ad..3a21ef12 100644 --- a/sas/tests/test_api.py +++ b/sas/tests/test_api.py @@ -75,7 +75,8 @@ class TestPictureSearch(TestSas): assert [i["id"] for i in res.json()["results"]] == expected def test_not_subscribed_user(self): - """Test that a user that is not subscribed can only its own pictures.""" + """Test that a user that never subscribed can only its own pictures.""" + self.user_a.subscriptions.all().delete() self.client.force_login(self.user_a) res = self.client.get( reverse("api:pictures") + f"?users_identified={self.user_a.id}" diff --git a/sas/views.py b/sas/views.py index 1ef7afe0..d45c13d1 100644 --- a/sas/views.py +++ b/sas/views.py @@ -18,7 +18,6 @@ from ajax_select.fields import AutoCompleteSelectMultipleField from django import forms from django.conf import settings from django.core.exceptions import PermissionDenied -from django.core.paginator import InvalidPage, Paginator from django.http import Http404, HttpResponse from django.shortcuts import get_object_or_404, redirect from django.urls import reverse, reverse_lazy @@ -318,9 +317,7 @@ class ModerationView(TemplateView): kwargs["albums_to_moderate"] = Album.objects.filter( is_moderated=False, is_in_sas=True, is_folder=True ).order_by("id") - kwargs["pictures"] = Picture.objects.filter( - is_moderated=False, is_in_sas=True, is_folder=False - ) + kwargs["pictures"] = Picture.objects.filter(is_moderated=False) kwargs["albums"] = Album.objects.filter( id__in=kwargs["pictures"].values("parent").distinct("parent") )