feat: User.all_groups

This commit is contained in:
imperosol
2026-02-20 18:46:37 +01:00
parent be1563f46f
commit 52759764a1
3 changed files with 22 additions and 17 deletions

View File

@@ -308,5 +308,5 @@ class PermissionOrClubBoardRequiredMixin(PermissionRequiredMixin):
if super().has_permission():
return True
return self.club is not None and any(
g.id == self.club.board_group_id for g in self.request.user.cached_groups
g.id == self.club.board_group_id for g in self.request.user.all_groups
)

View File

@@ -356,23 +356,30 @@ class User(AbstractUser):
)
if group_id is None:
return False
if group_id == settings.SITH_GROUP_SUBSCRIBERS_ID:
return self.is_subscribed
if group_id == settings.SITH_GROUP_ROOT_ID:
return self.is_root
return any(g.id == group_id for g in self.cached_groups)
return any(g.id == group_id for g in self.all_groups)
@cached_property
def cached_groups(self) -> list[Group]:
def all_groups(self) -> list[Group]:
"""Get the list of groups this user is in."""
return list(self.groups.all())
additional_groups = []
if self.is_subscribed:
additional_groups.append(settings.SITH_GROUP_SUBSCRIBERS_ID)
if self.is_superuser:
additional_groups.append(settings.SITH_GROUP_ROOT_ID)
qs = self.groups.all()
if additional_groups:
# This is somewhat counter-intuitive, but this query runs way faster with
# a UNION rather than a OR (in average, 0.25ms vs 14ms).
# For the why, cf. https://dba.stackexchange.com/questions/293836/why-is-an-or-statement-slower-than-union
qs = qs.union(Group.objects.filter(id__in=additional_groups))
return list(qs)
@cached_property
def is_root(self) -> bool:
if self.is_superuser:
return True
root_id = settings.SITH_GROUP_ROOT_ID
return any(g.id == root_id for g in self.cached_groups)
return any(g.id == root_id for g in self.all_groups)
@cached_property
def is_board_member(self) -> bool:
@@ -1099,9 +1106,7 @@ class PageQuerySet(models.QuerySet):
return self.filter(view_groups=settings.SITH_GROUP_PUBLIC_ID)
if user.has_perm("core.view_page"):
return self.all()
groups_ids = [g.id for g in user.cached_groups]
if user.is_subscribed:
groups_ids.append(settings.SITH_GROUP_SUBSCRIBERS_ID)
groups_ids = [g.id for g in user.all_groups]
return self.filter(view_groups__in=groups_ids)
@@ -1376,7 +1381,7 @@ class PageRev(models.Model):
return self.page.can_be_edited_by(user)
def is_owned_by(self, user: User) -> bool:
return any(g.id == self.page.owner_group_id for g in user.cached_groups)
return any(g.id == self.page.owner_group_id for g in user.all_groups)
def similarity_ratio(self, text: str) -> float:
"""Similarity ratio between this revision's content and the given text.

View File

@@ -418,16 +418,16 @@ class TestUserIsInGroup(TestCase):
group_in = baker.make(Group)
self.public_user.groups.add(group_in)
# clear the cached property `User.cached_groups`
self.public_user.__dict__.pop("cached_groups", None)
# clear the cached property `User.all_groups`
self.public_user.__dict__.pop("all_groups", None)
# Test when the user is in the group
with self.assertNumQueries(1):
with self.assertNumQueries(2):
self.public_user.is_in_group(pk=group_in.id)
with self.assertNumQueries(0):
self.public_user.is_in_group(pk=group_in.id)
group_not_in = baker.make(Group)
self.public_user.__dict__.pop("cached_groups", None)
self.public_user.__dict__.pop("all_groups", None)
# Test when the user is not in the group
with self.assertNumQueries(1):
self.public_user.is_in_group(pk=group_not_in.id)