Skip to content

Commit 35d94a2

Browse files
Add tests for visible_for_user filter method
1 parent b03b4a8 commit 35d94a2

File tree

1 file changed

+102
-9
lines changed

1 file changed

+102
-9
lines changed

ami/main/tests.py

Lines changed: 102 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import logging
33
from io import BytesIO
44

5+
from django.contrib.auth.models import AnonymousUser
56
from django.core.files.uploadedfile import SimpleUploadedFile
67
from django.db import connection, models
78
from django.test import TestCase, override_settings
@@ -11,9 +12,12 @@
1112
from rest_framework.test import APIRequestFactory, APITestCase
1213
from rich import print
1314

15+
from ami.exports.models import DataExport
1416
from ami.jobs.models import VALID_JOB_TYPES, Job
1517
from ami.main.models import (
18+
Classification,
1619
Deployment,
20+
Detection,
1721
Device,
1822
Event,
1923
Identification,
@@ -24,11 +28,14 @@
2428
SourceImage,
2529
SourceImageCollection,
2630
SourceImageUpload,
31+
Tag,
32+
TaxaList,
2733
Taxon,
2834
TaxonRank,
2935
group_images_into_events,
3036
)
3137
from ami.ml.models.pipeline import Pipeline
38+
from ami.ml.models.processing_service import ProcessingService
3239
from ami.ml.models.project_pipeline_config import ProjectPipelineConfig
3340
from ami.tests.fixtures.main import create_captures, create_occurrences, create_taxa, setup_test_project
3441
from ami.tests.fixtures.storage import populate_bucket
@@ -1971,7 +1978,7 @@ def setUp(self) -> None:
19711978
password="password123",
19721979
is_staff=True,
19731980
)
1974-
1981+
# Pre-create related test data
19751982
# Draft project with owner
19761983
self.project = Project.objects.create(
19771984
name="Draft Only Project",
@@ -1988,7 +1995,31 @@ def setUp(self) -> None:
19881995
self.project.members.add(self.member)
19891996
self.detail_url = f"/api/v2/projects/{self.project.pk}/"
19901997

1991-
#
1998+
Tag.objects.create(name="Test Tag", project=self.project)
1999+
DataExport.objects.create(
2000+
user=self.owner,
2001+
project=self.project,
2002+
format="json",
2003+
filters={},
2004+
filters_display={},
2005+
file_url="https://example.com/export.json",
2006+
record_count=123,
2007+
file_size=456789,
2008+
)
2009+
fake_image = SimpleUploadedFile("test.jpg", b"fake image content", content_type="image/jpeg")
2010+
SourceImageUpload.objects.create(image=fake_image, deployment=self.deployment)
2011+
occurrence = Occurrence.objects.filter(deployment=self.deployment).first()
2012+
Identification.objects.create(occurrence=occurrence)
2013+
S3StorageSource.objects.create(
2014+
name="Test S3 Source",
2015+
bucket="test-bucket",
2016+
access_key="fake-access-key",
2017+
secret_key="fake-secret-key",
2018+
project=self.project,
2019+
)
2020+
taxon = Taxon.objects.create(name="Draft Taxon")
2021+
taxon.projects.add(self.project)
2022+
self.non_draft_project = Project.objects.filter(draft=False).first()
19922023

19932024
def _auth_get(self, user, url):
19942025
self.client.force_authenticate(user)
@@ -2073,12 +2104,74 @@ def test_deployment_list_draft_project(self):
20732104
ids = [d["id"] for d in response.data["results"]]
20742105
assert self.deployment.pk not in ids
20752106

2076-
def test_access_after_publishing_project(self):
2077-
self.project.draft = False
2078-
self.project.save()
2107+
def test_visible_for_user_across_all_models(self):
2108+
all_users = {
2109+
"superuser": self.superuser,
2110+
"owner": self.owner,
2111+
"member": self.member,
2112+
"outsider": self.outsider,
2113+
"anonymous": AnonymousUser(),
2114+
}
2115+
2116+
project_related_models = [
2117+
Project,
2118+
Device,
2119+
Site,
2120+
Deployment,
2121+
Event,
2122+
S3StorageSource,
2123+
SourceImage,
2124+
Occurrence,
2125+
Tag,
2126+
SourceImageCollection,
2127+
Job,
2128+
DataExport,
2129+
Taxon,
2130+
TaxaList,
2131+
ProcessingService,
2132+
Pipeline,
2133+
SourceImageUpload,
2134+
Identification,
2135+
Classification,
2136+
Detection,
2137+
ProjectPipelineConfig,
2138+
]
2139+
2140+
for model in project_related_models:
2141+
project_accessor = model.get_project_accessor()
2142+
if project_accessor is None:
2143+
continue # skip models not related to a project
2144+
2145+
# Filter only objects from the test draft project
2146+
try:
2147+
if model == Project:
2148+
draft_queryset = model.objects.filter(draft=True)
2149+
non_draft_queryset = model.objects.filter(draft=False)
2150+
else:
2151+
draft_queryset = model.objects.filter(**{f"{project_accessor}": self.project})
2152+
non_draft_queryset = model.objects.filter(**{f"{project_accessor}": self.non_draft_project})
2153+
except Exception as e:
2154+
raise AssertionError(
2155+
f"Failed to filter querysets for {model.__name__} using accessor '{project_accessor}': {e}"
2156+
)
2157+
2158+
self.assertTrue(
2159+
draft_queryset.exists(),
2160+
f"No instances found for model {model.__name__} tied to the draft project",
2161+
)
2162+
2163+
for role, user in all_users.items():
2164+
visible_ids = list(draft_queryset.visible_for_user(user).values_list("id", flat=True))
2165+
non_draft_ids = set(non_draft_queryset.values_list("id", flat=True))
2166+
is_draft_viewer = role in {"superuser", "owner", "member"}
2167+
2168+
for instance in draft_queryset:
2169+
msg = f"{model.__name__} visible_for_user failed for role={role}"
20792170

2080-
project_url = f"/api/v2/projects/{self.project.pk}/"
2081-
deployment_url = f"/api/v2/deployments/{self.deployment.pk}/"
2171+
is_in_non_draft = instance.id in non_draft_ids
2172+
should_be_visible = is_draft_viewer or is_in_non_draft
20822173

2083-
assert self._auth_get(self.outsider, project_url).status_code == 200
2084-
assert self._auth_get(self.outsider, deployment_url).status_code == 200
2174+
if should_be_visible:
2175+
self.assertIn(instance.id, visible_ids, msg)
2176+
else:
2177+
self.assertNotIn(instance.id, visible_ids, msg)

0 commit comments

Comments
 (0)