Skip to content

Commit

Permalink
fix API participation permissions, allow filtering by event type (#1249)
Browse files Browse the repository at this point in the history
* correct handling of permissions on participation endpoint

* add filter for event type on participation endpoint

* add FilterSet, add tests
  • Loading branch information
jeriox authored Apr 2, 2024
1 parent 5025baa commit 70eda99
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 2 deletions.
29 changes: 29 additions & 0 deletions ephios/api/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from django_filters import DateTimeFilter, ModelChoiceFilter
from django_filters.rest_framework import FilterSet
from guardian.shortcuts import get_objects_for_user
from rest_framework.filters import BaseFilterBackend

from ephios.core.models import EventType, LocalParticipation


class ParticipationPermissionFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
events = get_objects_for_user(request.user, "core.view_event")
return queryset.filter(shift__event__in=events)


class ParticipationFilterSet(FilterSet):
# we cannot use gettext_lazy as it breaks sphinxcontrib.openapi (https://github.com/sphinx-contrib/openapi/issues/153)
event_type = ModelChoiceFilter(
field_name="shift__event__type", label="event type", queryset=EventType.objects.all()
)
start_gte = DateTimeFilter(field_name="start_time", lookup_expr="gte", label="start time after")
start_lte = DateTimeFilter(
field_name="start_time", lookup_expr="lte", label="start time before"
)
end_gte = DateTimeFilter(field_name="end_time", lookup_expr="gte", label="end time after")
end_lte = DateTimeFilter(field_name="end_time", lookup_expr="lte", label="end time before")

class Meta:
model = LocalParticipation
fields = ["state"]
5 changes: 3 additions & 2 deletions ephios/api/views/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from rest_framework.viewsets import GenericViewSet
from rest_framework_guardian.filters import ObjectPermissionsFilter

from ephios.api.filters import ParticipationFilterSet, ParticipationPermissionFilter
from ephios.api.views.events import ParticipationSerializer
from ephios.core.models import LocalParticipation, Qualification, UserProfile
from ephios.core.services.qualification import collect_all_included_qualifications
Expand Down Expand Up @@ -103,8 +104,8 @@ class UserByMailView(RetrieveModelMixin, GenericViewSet):
class UserParticipationView(viewsets.ReadOnlyModelViewSet):
serializer_class = ParticipationSerializer
permission_classes = [IsAuthenticatedOrTokenHasScope]
filter_backends = [ObjectPermissionsFilter, DjangoFilterBackend]
filterset_fields = ["state"]
filter_backends = [ParticipationPermissionFilter, DjangoFilterBackend]
filterset_class = ParticipationFilterSet
required_scopes = ["CONFIDENTIAL_READ"]

def get_queryset(self):
Expand Down
55 changes: 55 additions & 0 deletions tests/api/test_participation_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from django.urls import reverse
from guardian.shortcuts import remove_perm

from ephios.core.models import AbstractParticipation, LocalParticipation


def test_participation_list_permissions(django_app, event, planner, groups, volunteer, manager):
LocalParticipation.objects.create(
user=volunteer, shift=event.shifts.first(), state=AbstractParticipation.States.CONFIRMED
)
response = django_app.get(
reverse("api:user-participations-list", kwargs=dict(user=volunteer.pk)),
user=planner,
status=200,
)
assert event.title in response

# make event invisible to volunteers
_, planners, volunteers = groups
remove_perm("view_event", planners, event)
remove_perm("view_event", volunteers, event)
remove_perm("view_event", planner, event)

response = django_app.get(
reverse("api:user-participations-list", kwargs=dict(user=volunteer.pk)),
user=planner,
status=200,
)
assert event.title not in response
assert event.title in django_app.get(
reverse("api:user-participations-list", kwargs=dict(user=volunteer.pk)),
user=manager,
status=200,
)


def test_participation_list_filter(
django_app, event, planner, groups, volunteer, manager, training_event_type
):
LocalParticipation.objects.create(
user=volunteer, shift=event.shifts.first(), state=AbstractParticipation.States.CONFIRMED
)
response = django_app.get(
reverse("api:user-participations-list", kwargs=dict(user=volunteer.pk)),
user=planner,
status=200,
)
assert event.title in response

response = django_app.get(
f"{reverse('api:user-participations-list', kwargs=dict(user=volunteer.pk))}?event_type={training_event_type.pk}",
user=planner,
status=200,
)
assert event.title not in response

0 comments on commit 70eda99

Please sign in to comment.