(teams) return parent teams in API

Also return the parent teams in the user's team endpoints.

This is a first implementation which returns a flat list
of teams (not a tree). This is not really helpful, but
it allows to create hierarchical teams manually (via
admin) if an organization needs it.
This commit is contained in:
Quentin BEY
2024-12-12 18:08:15 +01:00
committed by BEY Quentin
parent 182f9c1d17
commit 201864db3a
6 changed files with 418 additions and 4 deletions

View File

@@ -1,7 +1,11 @@
"""API endpoints"""
import operator
from functools import reduce
from django.conf import settings
from django.db.models import OuterRef, Q, Subquery
from django.db.models import OuterRef, Q, Subquery, Value
from django.db.models.functions import Coalesce
from rest_framework import (
decorators,
@@ -299,13 +303,21 @@ class TeamViewSet(
permission_classes = [permissions.AccessPermission]
serializer_class = serializers.TeamSerializer
filter_backends = [filters.OrderingFilter]
ordering_fields = ["created_at"]
ordering_fields = ["created_at", "name", "path"]
ordering = ["-created_at"]
queryset = models.Team.objects.all()
pagination_class = None
def get_queryset(self):
"""Custom queryset to get user related teams."""
teams_queryset = models.Team.objects.filter(
accesses__user=self.request.user,
)
depth_path = teams_queryset.values("depth", "path")
if not depth_path:
return models.Team.objects.none()
user_role_query = models.TeamAccess.objects.filter(
user=self.request.user, team=OuterRef("pk")
).values("role")[:1]
@@ -313,9 +325,32 @@ class TeamViewSet(
return (
models.Team.objects.prefetch_related("accesses", "service_providers")
.filter(
accesses__user=self.request.user,
reduce(
operator.or_,
(
Q(
# The team the user has access to
depth=d["depth"],
path=d["path"],
)
| Q(
# The parent team the user has access to
depth__lt=d["depth"],
path__startswith=d["path"][: models.Team.steplen],
organization_id=self.request.user.organization_id,
)
for d in depth_path
),
),
)
# Abilities are computed based on logged-in user's role for the team
# and if the user does not have access, it's ok to consider them as a member
# because it's a parent team.
.annotate(
user_role=Coalesce(
Subquery(user_role_query), Value(models.RoleChoices.MEMBER.value)
)
)
.annotate(user_role=Subquery(user_role_query))
)
def perform_create(self, serializer):