From 410e440bd61d76d4fe8861ddde01a2b4d83523d6 Mon Sep 17 00:00:00 2001 From: stumpylog <797416+stumpylog@users.noreply.github.com> Date: Thu, 30 Jul 2026 10:53:02 -0700 Subject: [PATCH] fix(benchmark): fully clear users/groups on reset, grant perf_target model perms --- src/paperless_benchmark/db.py | 14 ++++++++------ src/paperless_benchmark/seeding.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/paperless_benchmark/db.py b/src/paperless_benchmark/db.py index c68c39b33..d406dd3e4 100644 --- a/src/paperless_benchmark/db.py +++ b/src/paperless_benchmark/db.py @@ -30,17 +30,19 @@ def _reset_table_names() -> list[str]: ] -def _delete_non_superusers() -> None: +def _delete_all_users_and_groups() -> None: from django.contrib.auth import get_user_model + from django.contrib.auth.models import Group - get_user_model().objects.filter(is_superuser=False).delete() + get_user_model().objects.all().delete() + Group.objects.all().delete() def _reset_postgresql() -> None: tables = _reset_table_names() with connection.cursor() as cursor: cursor.execute(f"TRUNCATE TABLE {', '.join(tables)} RESTART IDENTITY CASCADE;") - _delete_non_superusers() + _delete_all_users_and_groups() def _reset_mariadb() -> None: @@ -55,7 +57,7 @@ def _reset_mariadb() -> None: cursor.execute(f"TRUNCATE TABLE {table};") finally: cursor.execute("SET FOREIGN_KEY_CHECKS = 1;") - _delete_non_superusers() + _delete_all_users_and_groups() def _reset_sqlite() -> None: @@ -70,14 +72,14 @@ def _reset_sqlite() -> None: Correspondent.objects.all().delete() DocumentType.objects.all().delete() StoragePath.objects.all().delete() - _delete_non_superusers() + _delete_all_users_and_groups() def reset_benchmark_data() -> None: """ Remove all previously-seeded benchmark data (documents, tags, correspondents, document types, storage paths, guardian permission - rows, and non-superuser users) so a fresh `benchmark seed` run starts + rows, users, and groups) so a fresh `benchmark seed` run starts from an empty slate. Dispatches per-backend because TRUNCATE syntax and cascade behavior differ across the 3 supported databases. """ diff --git a/src/paperless_benchmark/seeding.py b/src/paperless_benchmark/seeding.py index 1be29de98..76f30e318 100644 --- a/src/paperless_benchmark/seeding.py +++ b/src/paperless_benchmark/seeding.py @@ -113,12 +113,40 @@ class SeededData: storage_paths: tuple[StoragePath, ...] +def _grant_model_level_permissions(user) -> None: + """ + Grant perf_target Django model-level view/add/change permissions on + Document and Tag, on top of the per-object guardian grants seeding + creates elsewhere. DRF's PaperlessObjectPermissions checks model-level + permissions before guardian's object-level ones are ever consulted, so + without this perf_target gets a blanket 403 on /api/documents/ and + /api/tags/ regardless of which documents guardian says it can see. + """ + from django.contrib.auth.models import Permission + from django.contrib.contenttypes.models import ContentType + + from documents.models import Document + from documents.models import Tag + + for model in (Document, Tag): + content_type = ContentType.objects.get_for_model(model) + codenames = [ + f"{action}_{model._meta.model_name}" for action in ("view", "add", "change") + ] + perms = Permission.objects.filter( + content_type=content_type, + codename__in=codenames, + ) + user.user_permissions.add(*perms) + + def _create_users_and_groups(counts: _TierCounts): from django.contrib.auth.models import Group from documents.tests.factories import UserFactory perf_target = UserFactory.create(username="perf_target") + _grant_model_level_permissions(perf_target) perf_admin = UserFactory.create(username="perf_admin", superuser=True) other_users = tuple(UserFactory.create_batch(counts.other_users)) groups = tuple(