From e845934243aa4e367ac12474a37546b8b9ca4d17 Mon Sep 17 00:00:00 2001 From: irtazaakram Date: Tue, 29 Aug 2023 12:11:10 +0500 Subject: [PATCH] fix: inheritance issues --- registrar/apps/api/v3/views.py | 103 ++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/registrar/apps/api/v3/views.py b/registrar/apps/api/v3/views.py index 4f98c5f0..9ec5803b 100644 --- a/registrar/apps/api/v3/views.py +++ b/registrar/apps/api/v3/views.py @@ -2,6 +2,9 @@ The public-facing REST API. """ import logging +from collections import defaultdict +from functools import cached_property +from django.http import Http404 from edx_api_doc_tools import query_parameter, schema_for from edx_rest_framework_extensions.auth.jwt.authentication import ( @@ -12,9 +15,12 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response +from registrar.apps.core import permissions as perms +from registrar.apps.core.auth_checks import get_programs_by_api_permission +from registrar.apps.core.models import Organization + from ..mixins import TrackViewMixin from ..serializers import DetailedProgramSerializer -from ..v1.views import ProgramListView from .pagination import CustomPagination @@ -38,7 +44,7 @@ **SCHEMA_COMMON_RESPONSES, }, ) -class ProgramListPaginationView(ProgramListView, TrackViewMixin, ListAPIView): +class ProgramListPaginationView(TrackViewMixin, ListAPIView): """ A view for listing program objects. @@ -60,3 +66,96 @@ def list(self, request): # pylint: disable=arguments-differ data = result.data return Response(data) + + def get_queryset(self): + """ + Get the Programs to be serialized and returned. + + Overrides ListAPIView.get_queryset. + """ + queryset = self.user_programs_by_api_permission[self.permission_filter] + if title_filter := self.request.GET.get('program_title'): + queryset = [program for program in queryset if title_filter.lower() in program.details.title.lower()] + return queryset + + def get_serializer_context(self): + """ + Get the extra data needed to serialize each Program. + + Overrides ListAPIView.get_serializer_context. + """ + return { + **super().get_serializer_context(), + "user_api_permissions_by_program": ( + self.user_api_permissions_by_program + ), + } + + @cached_property + def user_api_permissions_by_program(self): + """ + For each Program, the APIPermission that the user possesses on that program. + + Calculated and cached once per request. + + Returns: dict[Program: list[APIPermission]] + """ + result = defaultdict(list) + for api_permission, programs in self.user_programs_by_api_permission.items(): + for program in programs: + result[program].append(api_permission) + return dict(result) + + @cached_property + def user_programs_by_api_permission(self): + """ + For each APIPermission, the Programs on which the user possesses that APIPermission. + + Calculated and cached once per request. + + Returns: dict[APIPermission: list[Program]] + """ + return { + api_permission: list( + get_programs_by_api_permission( + user=self.request.user, + required_api_permission=api_permission, + organization_filter=self.organization_filter, + ) + ) + for api_permission in perms.API_PERMISSIONS + } + + @cached_property + def organization_filter(self): + """ + Return the organization by which results will be filtered, + no None if on filter specified. + + Raises 404 for non-existant organiation. + """ + if org_key := self.request.GET.get('org'): + try: + return Organization.objects.get(key=org_key) + except Organization.DoesNotExist as ex: + self.add_tracking_data(failure='org_not_found') + raise Http404() from ex + else: + return None + + @cached_property + def permission_filter(self): + """ + Return a list of APIPermission by which results will be filtered, + defaulting to API_READ_METADATA. + + Raises 404 for bad permission query param. + """ + perm_query_param = self.request.GET.get('user_has_perm', None) + if not perm_query_param: + return perms.API_READ_METADATA + try: + return perms.API_PERMISSIONS_BY_NAME[perm_query_param] + except KeyError as ex: + self.add_tracking_data(failure='no_such_perm') + raise Http404() from ex