Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add guest as url param for shared events, switch schema generation to drf-spectacular #1394

Merged
merged 3 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,6 @@

from django.core import management

management.call_command("generateschema", ["--file", "api/ephios-open-api-schema.yml"])
management.call_command(
"spectacular", ["--color", "--file", "api/ephios-open-api-schema.yml", "--api-version", "api"]
)
15 changes: 7 additions & 8 deletions ephios/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from django.conf import settings
from django.urls import include, path
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerSplitView
from oauth2_provider import views as oauth2_views
from rest_framework import routers
from rest_framework.schemas import get_schema_view

from ephios.api.access.views import (
AccessTokenCreateView,
Expand Down Expand Up @@ -91,13 +90,13 @@
),
path(
"schema/",
get_schema_view(
title="ephios",
description="ephios API",
version=settings.EPHIOS_VERSION,
url=settings.GET_SITE_URL(),
),
SpectacularAPIView.as_view(),
name="openapi-schema",
),
path(
jeriox marked this conversation as resolved.
Show resolved Hide resolved
"schema/swagger-ui/",
SpectacularSwaggerSplitView.as_view(url_name="openapi-schema"),
name="swagger-ui",
),
path("", include(router.urls)),
]
3 changes: 0 additions & 3 deletions ephios/api/views/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from rest_framework.generics import RetrieveAPIView
from rest_framework.mixins import RetrieveModelMixin
from rest_framework.relations import SlugRelatedField
from rest_framework.schemas.openapi import AutoSchema
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import GenericViewSet

Expand Down Expand Up @@ -66,7 +65,6 @@ class UserProfileMeView(RetrieveAPIView):
queryset = UserProfile.objects.all()
permission_classes = [IsAuthenticatedOrTokenHasScope]
required_scopes = ["ME_READ"]
schema = AutoSchema(operation_id_base="OwnUserProfile")

def get_object(self):
if self.request.user is None:
Expand Down Expand Up @@ -95,7 +93,6 @@ class UserByMailView(RetrieveModelMixin, GenericViewSet):
lookup_url_kwarg = "email"
lookup_field = "email"
lookup_value_regex = "[^/]+" # customize to allow dots (".") in the lookup value
schema = AutoSchema(operation_id_base="UserProfileByMail")


class UserParticipationView(viewsets.ReadOnlyModelViewSet):
Expand Down
10 changes: 8 additions & 2 deletions ephios/plugins/federation/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,16 @@ def all_participations(self):
return FederatedParticipation.objects.filter(federated_user=self.federated_user)

def reverse_signup_action(self, shift):
return reverse("federation:shift_signup", kwargs={"pk": shift.pk})
return reverse(
"federation:shift_signup",
kwargs={"pk": shift.pk, "guest": self.federated_user.federated_instance.pk},
)

def reverse_event_detail(self, event):
return reverse("federation:event_detail", kwargs={"pk": event.pk})
return reverse(
"federation:event_detail",
kwargs={"pk": event.pk, "guest": self.federated_user.federated_instance_id},
)

@property
def icon(self):
Expand Down
6 changes: 5 additions & 1 deletion ephios/plugins/federation/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,9 @@ class Meta:

def get_signup_url(self, obj):
return urljoin(
settings.GET_SITE_URL(), reverse("federation:event_detail", kwargs={"pk": obj.pk})
settings.GET_SITE_URL(),
reverse(
"federation:event_detail",
kwargs={"pk": obj.pk, "guest": self.context["federated_guest"].pk},
),
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@
{% translate "External events" %}
{% endblock %}

{% block messages %}
{% if "error" in request.GET %}
<div class="alert alert-warning" role="alert">
{% if request.GET.error == "oauth_error" %}
{% translate "An error occurred during the authentication at the other ephios instance. Please try again." %}
{% elif request.GET.error == "event_error" %}
{% translate "The desired event could not be accessed at the other ephios instance. Please try again." %}
{% else %}
{% translate "An unknown error has occured." %}
{% endif %}
</div>
{% endif %}
{% endblock %}

{% block content %}
<h1>{% translate "External events" %}</h1>
<ul class="list-group mb-3">
Expand All @@ -17,7 +31,7 @@ <h1>{% translate "External events" %}</h1>
</div>
</div>
<a class="w-100 text-reset py-2 event-list-item-link"
href="{{ event.signup_url }}?referrer={% site_url %}">
href="{{ event.signup_url }}">
<div class="grid-wrapper m-0 py-0 ps-2 pe-3">
<div class="grid-title">
<div>
Expand Down
6 changes: 4 additions & 2 deletions ephios/plugins/federation/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
name="external_event_list",
),
path(
"events/shared/<int:pk>/", frontend.FederatedEventDetailView.as_view(), name="event_detail"
"events/shared/<int:pk>/<int:guest>/",
frontend.FederatedEventDetailView.as_view(),
name="event_detail",
),
path(
"shifts/shared/<int:pk>/signup/",
"shifts/shared/<int:pk>/<int:guest>/signup/",
frontend.FederatedUserShiftActionView.as_view(),
name="shift_signup",
),
Expand Down
35 changes: 26 additions & 9 deletions ephios/plugins/federation/views/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ def get_queryset(self):
raise PermissionDenied from exc
return Event.objects.filter(federatedeventshare__shared_with=guest)

def get_serializer_context(self):
context = super().get_serializer_context()
context["federated_guest"] = self.request.auth.federatedguest
return context


class FederationOAuthView(View):
"""
Expand All @@ -81,20 +86,32 @@ class FederationOAuthView(View):

def get(self, request, *args, **kwargs):
try:
self.guest = (
FederatedGuest.objects.get(pk=self.request.session["federation_guest_pk"])
if "federation_guest_pk" in self.request.session.keys()
else FederatedGuest.objects.get(url=self.request.GET["referrer"])
)
guest_pk = self.request.session.get("federation_guest_pk", kwargs.get("guest"))
self.guest = FederatedGuest.objects.get(pk=guest_pk)
except (KeyError, FederatedGuest.DoesNotExist, MultipleObjectsReturned) as exc:
raise PermissionDenied from exc
if "error" in request.GET.keys():
return redirect(urljoin(self.guest.url, reverse("federation:external_event_list")))
elif "code" in request.GET.keys():
self._oauth_callback()
return redirect(
"federation:event_detail", pk=self.request.session.pop("federation_event")
urljoin(
urljoin(self.guest.url, reverse("federation:external_event_list")),
"?error=oauth_error",
)
)
elif "code" in request.GET.keys():
self._oauth_callback()
try:
return redirect(
"federation:event_detail",
pk=self.request.session["federation_event"],
guest=guest_pk,
)
except KeyError:
return redirect(
urljoin(
urljoin(self.guest.url, reverse("federation:external_event_list")),
"?error=event_error",
)
)
else:
return redirect(self._get_authorization_url())

Expand Down
3 changes: 1 addition & 2 deletions ephios/plugins/federation/views/frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,9 @@ class FederatedEventDetailView(CheckFederatedAccessTokenMixin, DetailView):
def get_object(self, queryset=None):
obj = super().get_object(queryset)
try:
guest = self.request.session["federation_guest_pk"]
FederatedEventShare.objects.get(
event=obj,
shared_with__in=[FederatedGuest.objects.get(pk=guest)],
shared_with__in=[FederatedGuest.objects.get(pk=self.kwargs["guest"])],
)
except (KeyError, FederatedEventShare.DoesNotExist, FederatedGuest.DoesNotExist) as exc:
self.request.session.flush()
Expand Down
14 changes: 14 additions & 0 deletions ephios/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@
"guardian",
"oauth2_provider",
"rest_framework",
"drf_spectacular",
"drf_spectacular_sidecar",
"django_select2",
"djangoformsetjs",
"compressor",
Expand Down Expand Up @@ -430,6 +432,7 @@ def GET_USERCONTENT_QUOTA():
# django-rest-framework
DEFAULT_LISTVIEW_PAGINATION = 100
REST_FRAMEWORK = {
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.DjangoObjectPermissions"],
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.NamespaceVersioning",
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
Expand All @@ -440,6 +443,17 @@ def GET_USERCONTENT_QUOTA():
],
}

# drf-spectacular
SPECTACULAR_SETTINGS = {
"TITLE": "ephios API",
"DESCRIPTION": "ephios REST API",
"VERSION": EPHIOS_VERSION,
"SERVE_INCLUDE_SCHEMA": False,
"SWAGGER_UI_DIST": "SIDECAR",
"SWAGGER_UI_FAVICON_HREF": "SIDECAR",
"REDOC_DIST": "SIDECAR",
}

# Like UserProfile, these models are implemented using djangos private swappable API
# due to a shaky implementation in django-oauth-toolkit, we need to customize all models,
# although we only want to customize the AccessToken model
Expand Down
Loading