diff --git a/gateway/api/views.py b/gateway/api/views.py index 39140dcad..75ed4c426 100644 --- a/gateway/api/views.py +++ b/gateway/api/views.py @@ -115,9 +115,13 @@ def get_queryset(self): author = self.request.user title = self.request.query_params.get("title") provider_name = self.request.query_params.get("provider") + type_filter = self.request.query_params.get("filter") author_programs = self._get_program_queryset_for_title_and_provider( - author=author, title=title, provider_name=provider_name + author=author, + title=title, + provider_name=provider_name, + type_filter=type_filter, ).distinct() author_programs_count = author_programs.count() @@ -305,7 +309,7 @@ def get_by_title(self, request, title): provider_name = self.request.query_params.get("provider") result_program = self._get_program_queryset_for_title_and_provider( - author=author, title=title, provider_name=provider_name + author=author, title=title, provider_name=provider_name, type_filter=None ).first() if result_program: @@ -314,7 +318,11 @@ def get_by_title(self, request, title): return Response(status=404) def _get_program_queryset_for_title_and_provider( - self, author, title: str, provider_name: Optional[str] + self, + author, + title: str, + provider_name: Optional[str], + type_filter: Optional[str], ): """Returns queryset for program for gived request, title and provider.""" view_program_permission = Permission.objects.get( @@ -322,6 +330,26 @@ def _get_program_queryset_for_title_and_provider( ) # Groups logic + if type_filter: + if type_filter == "catalog": + view_permission_criteria = Q(permissions=view_program_permission) + groups_with_view_permissions = Group.objects.filter( + view_permission_criteria + ) + groups_with_view_permissions_criteria = Q( + instances__in=groups_with_view_permissions + ) + provider_exists_criteria = ~Q(provider=None) + result_queryset = Program.objects.filter( + groups_with_view_permissions_criteria & provider_exists_criteria + ) + return result_queryset + if type_filter == "serverless": + result_queryset = Program.objects.filter( + Q(author=author) & Q(provider=None) + ) + return result_queryset + user_criteria = Q(user=author) view_permission_criteria = Q(permissions=view_program_permission) author_groups_with_view_permissions = Group.objects.filter( @@ -357,7 +385,6 @@ def _get_program_queryset_for_title_and_provider( result_queryset = Program.objects.filter( author_criteria | author_groups_with_view_permissions_criteria ) - return result_queryset @action(methods=["GET"], detail=True) @@ -405,6 +432,16 @@ def get_serializer_class(self): return self.serializer_class def get_queryset(self): + type_filter = self.request.query_params.get("filter") + if type_filter: + if type_filter == "catalog": + user_criteria = Q(author=self.request.user) + provider_exists_criteria = ~Q(program__provider=None) + return Job.objects.filter(user_criteria & provider_exists_criteria) + if type_filter == "serverless": + user_criteria = Q(author=self.request.user) + provider_not_exists_criteria = Q(program__provider=None) + return Job.objects.filter(user_criteria & provider_not_exists_criteria) return Job.objects.filter(author=self.request.user).order_by("-created") def retrieve(self, request, pk=None): # pylint: disable=unused-argument diff --git a/gateway/tests/api/test_job.py b/gateway/tests/api/test_job.py index 32559755d..e29d0f100 100644 --- a/gateway/tests/api/test_job.py +++ b/gateway/tests/api/test_job.py @@ -38,6 +38,39 @@ def test_job_list(self): jobs_response.data.get("results")[0].get("result"), '{"somekey":1}' ) + def test_job_catalog_list(self): + """Tests job list authorized.""" + self._authorize() + + jobs_response = self.client.get( + reverse("v1:jobs-list"), {"filter": "catalog"}, format="json" + ) + self.assertEqual(jobs_response.status_code, status.HTTP_200_OK) + self.assertEqual(jobs_response.data.get("count"), 1) + self.assertEqual(jobs_response.data.get("results")[0].get("status"), "QUEUED") + self.assertEqual( + jobs_response.data.get("results")[0].get("result"), '{"somekey":1}' + ) + + def test_job_serverless_list(self): + """Tests job list authorized.""" + self._authorize() + + jobs_response = self.client.get( + reverse("v1:jobs-list"), {"filter": "serverless"}, format="json" + ) + self.assertEqual(jobs_response.status_code, status.HTTP_200_OK) + self.assertEqual(jobs_response.data.get("count"), 2) + job_status = jobs_response.data.get("results")[0].get("status") + if job_status == "SUCCEEDED": + self.assertEqual( + jobs_response.data.get("results")[0].get("result"), '{"somekey":1}' + ) + elif job_status == "QUEUED": + self.assertEqual( + jobs_response.data.get("results")[0].get("result"), '{"somekey":2}' + ) + def test_job_detail(self): """Tests job detail authorized.""" self._authorize() diff --git a/gateway/tests/api/test_v1_program.py b/gateway/tests/api/test_v1_program.py index 9cdd2fe89..a5391fc02 100644 --- a/gateway/tests/api/test_v1_program.py +++ b/gateway/tests/api/test_v1_program.py @@ -57,6 +57,44 @@ def test_provider_programs_list(self): "Docker-Image-Program", ) + def test_provider_programs_catalog_list(self): + """Tests programs list authorized.""" + + user = models.User.objects.get(username="test_user_4") + self.client.force_authenticate(user=user) + + programs_response = self.client.get( + reverse("v1:programs-list"), {"filter": "catalog"}, format="json" + ) + + self.assertEqual(programs_response.status_code, status.HTTP_200_OK) + self.assertEqual(len(programs_response.data), 1) + self.assertEqual( + programs_response.data[0].get("provider"), + "ibm", + ) + self.assertEqual( + programs_response.data[0].get("title"), + "Docker-Image-Program-2", + ) + + def test_provider_programs_serverless_list(self): + """Tests programs list authorized.""" + + user = models.User.objects.get(username="test_user_3") + self.client.force_authenticate(user=user) + + programs_response = self.client.get( + reverse("v1:programs-list"), {"filter": "serverless"}, format="json" + ) + + self.assertEqual(programs_response.status_code, status.HTTP_200_OK) + self.assertEqual(len(programs_response.data), 1) + self.assertEqual( + programs_response.data[0].get("title"), + "Program", + ) + def test_program_list_with_title_query_parameter(self): """Tests program list filtered with title.""" user = models.User.objects.get(username="test_user") diff --git a/gateway/tests/fixtures/fixtures.json b/gateway/tests/fixtures/fixtures.json index 7eeda1a34..d851798fb 100644 --- a/gateway/tests/fixtures/fixtures.json +++ b/gateway/tests/fixtures/fixtures.json @@ -35,7 +35,21 @@ "password": "pbkdf2_sha256$390000$kcex1rxhZg6VVJYkx71cBX$e4ns0xDykbO6Dz6j4nZ4uNusqkB9GVpojyegPv5/9KM=", "is_active": true, "groups": [ - 100 + 100, + 101 + ] + } + }, + { + "model": "auth.user", + "pk": 4, + "fields": { + "email": "test_user_4@email.com", + "username": "test_user_4", + "password": "pbkdf2_sha256$390000$kcex1rxhZg6VVJYkx71cBX$e4ns0xDykbO6Dz6j4nZ4uNusqkB9GVpojyegPv5/9KM=", + "is_active": true, + "groups": [ + 101 ] } }, @@ -67,6 +81,37 @@ "provider": "bfe8aa6a-2127-4123-bf57-5b547293cbea" } }, + { + "model": "api.program", + "pk": "6160a2ff-e482-443d-af23-15110b646ae3", + "fields": { + "created": "2023-02-01T15:30:43.281796Z", + "title": "Docker-Image-Program-2", + "image": "icr.io/awesome-namespace/awesome-title", + "author": 3, + "env_vars": "{\"PROGRAM_ENV1\": \"VALUE1\", \"PROGRAM_ENV2\": \"VALUE2\"}", + "provider": "bfe8aa6a-2127-4123-bf57-5b547293cbeb", + "instances": [ + 100, + 101 + ] + } + }, + { + "model": "api.program", + "pk": "1a7947f9-6ae8-4e3d-ac1e-e7d608deec83", + "fields": { + "created": "2023-02-01T15:30:43.281796Z", + "title": "Program", + "entrypoint": "program.py", + "artifact": "path", + "author": 3, + "env_vars": "{\"PROGRAM_ENV1\": \"VALUE1\", \"PROGRAM_ENV2\": \"VALUE2\"}", + "instances": [ + 100 + ] + } + }, { "model": "api.job", "pk": "1a7947f9-6ae8-4e3d-ac1e-e7d608deec82", @@ -85,7 +130,7 @@ "fields": { "program": "1a7947f9-6ae8-4e3d-ac1e-e7d608deec82", "created": "2023-02-01T15:30:43.281796Z", - "result": "{\"somekey\":1}", + "result": "{\"somekey\":2}", "status": "QUEUED", "author": 1 }