Skip to content
Snippets Groups Projects
Commit a6a649d4 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch '877-trailing-slash-api' into 'develop'

Fix #877: Ensure API urls answer with and without a trailing slash

Closes #877

See merge request funkwhale/funkwhale!817
parents 98c6e103 53b826c8
No related branches found
No related tags found
No related merge requests found
Showing
with 75 additions and 32 deletions
......@@ -6,11 +6,12 @@ from rest_framework_jwt import views as jwt_views
from funkwhale_api.activity import views as activity_views
from funkwhale_api.common import views as common_views
from funkwhale_api.common import routers as common_routers
from funkwhale_api.music import views
from funkwhale_api.playlists import views as playlists_views
from funkwhale_api.subsonic.views import SubsonicViewSet
router = routers.SimpleRouter()
router = common_routers.OptionalSlashRouter()
router.register(r"settings", GlobalPreferencesViewSet, basename="settings")
router.register(r"activity", activity_views.ActivityViewSet, "activity")
router.register(r"tags", views.TagViewSet, "tags")
......@@ -79,8 +80,8 @@ v1_patterns += [
r"^oauth/",
include(("funkwhale_api.users.oauth.urls", "oauth"), namespace="oauth"),
),
url(r"^token/$", jwt_views.obtain_jwt_token, name="token"),
url(r"^token/refresh/$", jwt_views.refresh_jwt_token, name="token_refresh"),
url(r"^token/?$", jwt_views.obtain_jwt_token, name="token"),
url(r"^token/refresh/?$", jwt_views.refresh_jwt_token, name="token_refresh"),
]
urlpatterns = [
......
from rest_framework.routers import SimpleRouter
class OptionalSlashRouter(SimpleRouter):
def __init__(self):
super().__init__()
self.trailing_slash = "/?"
from rest_framework import routers
from funkwhale_api.common import routers
from . import views
router = routers.SimpleRouter()
router = routers.OptionalSlashRouter()
router.register(r"tracks", views.TrackFavoriteViewSet, "tracks")
urlpatterns = router.urls
from rest_framework import routers
from funkwhale_api.common import routers
from . import api_views
router = routers.SimpleRouter()
router = routers.OptionalSlashRouter()
router.register(r"fetches", api_views.FetchViewSet, "fetches")
router.register(r"follows/library", api_views.LibraryFollowViewSet, "library-follows")
router.register(r"inbox", api_views.InboxItemViewSet, "inbox")
......
from rest_framework import routers
from funkwhale_api.common import routers
from . import views
router = routers.SimpleRouter()
router = routers.OptionalSlashRouter()
router.register(r"listenings", views.ListeningViewSet, "listenings")
urlpatterns = router.urls
from django.conf.urls import url
from rest_framework import routers
from funkwhale_api.common import routers
from . import views
admin_router = routers.SimpleRouter()
admin_router = routers.OptionalSlashRouter()
admin_router.register(r"admin/settings", views.AdminSettings, "admin-settings")
urlpatterns = [
url(r"^nodeinfo/2.0/$", views.NodeInfo.as_view(), name="nodeinfo-2.0"),
url(r"^settings/$", views.InstanceSettings.as_view(), name="settings"),
url(r"^nodeinfo/2.0/?$", views.NodeInfo.as_view(), name="nodeinfo-2.0"),
url(r"^settings/?$", views.InstanceSettings.as_view(), name="settings"),
] + admin_router.urls
from django.conf.urls import include, url
from rest_framework import routers
from funkwhale_api.common import routers
from . import views
federation_router = routers.SimpleRouter()
federation_router = routers.OptionalSlashRouter()
federation_router.register(r"domains", views.ManageDomainViewSet, "domains")
library_router = routers.SimpleRouter()
library_router = routers.OptionalSlashRouter()
library_router.register(r"albums", views.ManageAlbumViewSet, "albums")
library_router.register(r"artists", views.ManageArtistViewSet, "artists")
library_router.register(r"libraries", views.ManageLibraryViewSet, "libraries")
library_router.register(r"tracks", views.ManageTrackViewSet, "tracks")
library_router.register(r"uploads", views.ManageUploadViewSet, "uploads")
moderation_router = routers.SimpleRouter()
moderation_router = routers.OptionalSlashRouter()
moderation_router.register(
r"instance-policies", views.ManageInstancePolicyViewSet, "instance-policies"
)
users_router = routers.SimpleRouter()
users_router = routers.OptionalSlashRouter()
users_router.register(r"users", views.ManageUserViewSet, "users")
users_router.register(r"invitations", views.ManageInvitationViewSet, "invitations")
other_router = routers.SimpleRouter()
other_router = routers.OptionalSlashRouter()
other_router.register(r"accounts", views.ManageActorViewSet, "accounts")
urlpatterns = [
......
from rest_framework import routers
from funkwhale_api.common import routers
from . import views
router = routers.SimpleRouter()
router = routers.OptionalSlashRouter()
router.register(r"content-filters", views.UserFilterViewSet, "content-filters")
urlpatterns = router.urls
from django.conf.urls import url
from rest_framework import routers
from funkwhale_api.common import routers
from . import views
router = routers.SimpleRouter()
router = routers.OptionalSlashRouter()
router.register(r"search", views.SearchViewSet, "search")
urlpatterns = [
url(
......
from rest_framework import routers
from funkwhale_api.common import routers
from . import views
router = routers.SimpleRouter()
router = routers.OptionalSlashRouter()
router.register(r"sessions", views.RadioSessionViewSet, "sessions")
router.register(r"radios", views.RadioViewSet, "radios")
router.register(r"tracks", views.RadioSessionTrackViewSet, "tracks")
......
from rest_framework import routers
from funkwhale_api.common import routers
from . import views
router = routers.SimpleRouter()
router = routers.OptionalSlashRouter()
router.register(r"users", views.UserViewSet, "users")
urlpatterns = router.urls
from django.conf.urls import url
from django.views.decorators.csrf import csrf_exempt
from rest_framework import routers
from funkwhale_api.common import routers
from . import views
router = routers.SimpleRouter()
router = routers.OptionalSlashRouter()
router.register(r"apps", views.ApplicationViewSet, "apps")
router.register(r"grants", views.GrantViewSet, "grants")
......
......@@ -8,12 +8,12 @@ from . import views
urlpatterns = [
url(r"^$", views.RegisterView.as_view(), name="rest_register"),
url(
r"^verify-email/$",
r"^verify-email/?$",
registration_views.VerifyEmailView.as_view(),
name="rest_verify_email",
),
url(
r"^change-password/$",
r"^change-password/?$",
rest_auth_views.PasswordChangeView.as_view(),
name="change_password",
),
......@@ -28,7 +28,7 @@ urlpatterns = [
# view from:
# djang-allauth https://github.com/pennersr/django-allauth/blob/master/allauth/account/views.py#L190
url(
r"^account-confirm-email/(?P<key>\w+)/$",
r"^account-confirm-email/(?P<key>\w+)/?$",
TemplateView.as_view(),
name="account_confirm_email",
),
......
import pytest
from django import urls
@pytest.mark.parametrize(
"url",
[
"/api/v1/artists",
"/api/v1/albums",
"/api/v1/tracks",
"/api/v1/libraries",
"/api/v1/uploads",
"/api/v1/playlists",
"/api/v1/favorites/tracks",
"/api/v1/auth/registration/verify-email",
"/api/v1/auth/registration/change-password",
"/api/v1/auth/registration/account-confirm-email/key",
"/api/v1/history/listenings",
"/api/v1/radios/sessions",
"/api/v1/users/users/me",
"/api/v1/federation/follows/library",
"/api/v1/manage/accounts",
"/api/v1/oauth/apps",
"/api/v1/moderation/content-filters",
"/api/v1/token",
"/api/v1/token/refresh",
"/api/v1/instance/settings",
"/api/v1/instance/nodeinfo/2.0",
],
)
@pytest.mark.parametrize("suffix", ["", "/"])
def test_optional_trailing_slash(url, suffix):
match = urls.resolve(url + suffix)
assert match is not None
Ensure API urls answer with and without a trailing slash (#877)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment