Skip to content

Commit

Permalink
Add filtering to api-fixes branch (#140)
Browse files Browse the repository at this point in the history
* Add API view for grants.

* Add email to service roles.

* Simple filtering for service and category

* Try to use DjangoFilterBackend filterset_fields

* Tidy filtering of queryset

* Remove django filter backend import

* Remove trailing whitespace

* Black

* Make UserServices a nested route.

* Swap grants logic to it's own viewset.

* Add filtering for roles

* Add to swagger schema

* Test user API info

* Add test for filtering by category

* Add tests for query params

* Add tblib to testing dependencies

* Workaround unsupported %:z in python 3.11.

* Black, isort, remove redundant imports.

---------

Co-authored-by: Alex Manning <[email protected]>
  • Loading branch information
nf679 and amanning9 authored Jun 3, 2024
1 parent 8900da8 commit 3ad45c9
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 29 deletions.
20 changes: 20 additions & 0 deletions jasmin_services/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,23 @@ class Meta:
"ceda_managed",
]
extra_kwargs = {"url": {"view_name": "category-services-detail", "lookup_field": "name"}}


class UserGrantSerializer(rf_serial.ModelSerializer):
"""Simple details about a service."""

service = ServiceListSerializer(source="access.role.service", read_only=True)
role = RoleListSerializer(source="access.role", read_only=True)

class Meta:
model = models.Grant
fields = [
"id",
"service",
"role",
"granted_at",
"expires",
"revoked",
"revoked_at",
"user_reason",
]
7 changes: 6 additions & 1 deletion jasmin_services/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import types

import django.urls
import rest_framework.routers as rf_routers
import rest_framework_nested.routers

Expand Down Expand Up @@ -40,6 +39,12 @@
apiviews.UserServicesViewSet,
basename="users-services",
)
# Register route to get user's grants.
users_router.register(
"grants",
apiviews.UserGrantsViewSet,
basename="users-grants",
)

# Create a route for accesing service by id.
primary_router.register(
Expand Down
59 changes: 58 additions & 1 deletion jasmin_services/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import datetime as dt

import django.contrib.auth
import django.db.models as dj_models
import django.utils.timezone
import drf_spectacular.utils
Expand Down Expand Up @@ -173,6 +172,64 @@ def get_queryset(self):
).distinct()


@drf_spectacular.utils.extend_schema_view(
list=drf_spectacular.utils.extend_schema(
parameters=[
drf_spectacular.utils.OpenApiParameter(
name="service",
required=False,
type=str,
description="Name of the service you would like to filter the grants for.",
),
drf_spectacular.utils.OpenApiParameter(
name="category",
required=False,
type=str,
description="Name of the category you would like to filter the grants for.",
),
drf_spectacular.utils.OpenApiParameter(
name="role",
required=False,
type=str,
description="Name of the role you would like to filter the grants for.",
),
]
),
)
class UserGrantsViewSet(rf_mixins.ListModelMixin, rf_viewsets.GenericViewSet):
"""Get the grants associated with a user."""

required_scopes = ["jasmin.services.userservices.all"]
serializer_class = serializers.UserGrantSerializer

def get_queryset(self):
queryset = models.Grant.objects.filter(
access__user__username=self.kwargs["user_username"],
revoked=False,
expires__gte=dt.datetime.now(),
).prefetch_related("access__role__service")

filter_params = {}

# Option to filter by service query param
service = self.request.query_params.get("service")
if service is not None:
filter_params["access__role__service__name"] = service

# Option to filter by category query param
category = self.request.query_params.get("category")
if category is not None:
filter_params["access__role__service__category__name"] = category

# Option to filter by grant role name
role = self.request.query_params.get("role")
if role is not None:
filter_params["access__role__name"] = role

queryset = queryset.filter(**filter_params)
return queryset


class CategoriesViewSet(
jasmin_django_utils.api.viewsets.ActionSerializerMixin,
rf_viewsets.ReadOnlyModelViewSet,
Expand Down
25 changes: 14 additions & 11 deletions jasmin_services/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,20 @@ def request_rejected(sender, instance, created, **kwargs):
def grant_created(sender, instance, created, **kwargs):
"""Notifies the user when a grant is created."""
if created and instance.active and not re.match(r"train\d{3}", instance.access.user.username):
instance.access.user.notify(
"grant_created",
instance,
reverse(
"jasmin_services:service_details",
kwargs={
"category": instance.access.role.service.category.name,
"service": instance.access.role.service.name,
},
),
)
try:
instance.access.user.notify(
"grant_created",
instance,
reverse(
"jasmin_services:service_details",
kwargs={
"category": instance.access.role.service.category.name,
"service": instance.access.role.service.name,
},
),
)
except AttributeError:
pass


@receiver(signals.post_save, sender=Grant)
Expand Down
Loading

0 comments on commit 3ad45c9

Please sign in to comment.