BAsic logic for adding view through a plugin
This commit is contained in:
parent
b853f38c74
commit
cc40492f20
|
@ -286,6 +286,7 @@ MIDDLEWARE = tuple(ADDITIONAL_MIDDLEWARES_BEFORE) + (
|
|||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"funkwhale_api.users.middleware.RecordActivityMiddleware",
|
||||
"funkwhale_api.common.middleware.ThrottleStatusMiddleware",
|
||||
"funkwhale_api.common.plugins.PluginViewMiddleware",
|
||||
)
|
||||
|
||||
# DEBUG
|
||||
|
@ -555,6 +556,7 @@ Delay in seconds before uploaded but unattached attachements are pruned from the
|
|||
# ------------------------------------------------------------------------------
|
||||
ROOT_URLCONF = "config.urls"
|
||||
SPA_URLCONF = "config.spa_urls"
|
||||
PLUGINS_URLCONF = "funkwhale_api.common.plugins"
|
||||
ASGI_APPLICATION = "config.routing.application"
|
||||
|
||||
# This ensures that Django will be able to detect a secure connection
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import json
|
||||
|
||||
from django import http
|
||||
|
||||
from .plugin import PLUGIN
|
||||
|
||||
|
||||
@PLUGIN.register_api_view(path="prometheus")
|
||||
def prometheus(request):
|
||||
stats = get_stats()
|
||||
return http.HttpResponse(json.dumps(stats))
|
||||
|
||||
|
||||
def get_stats():
|
||||
return {"foo": "bar"}
|
|
@ -0,0 +1,5 @@
|
|||
from funkwhale_api.common import plugins
|
||||
|
||||
|
||||
class Plugin(plugins.Plugin):
|
||||
name = "prometheus"
|
|
@ -0,0 +1,45 @@
|
|||
from django.apps import AppConfig
|
||||
from django import urls
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
urlpatterns = []
|
||||
|
||||
|
||||
class PluginViewMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
response = self.get_response(request)
|
||||
if response.status_code == 404 and request.path.startswith("/plugins/"):
|
||||
match = urls.resolve(request.path, urlconf=settings.PLUGINS_URLCONF)
|
||||
response = match.func(request, *match.args, **match.kwargs)
|
||||
return response
|
||||
|
||||
|
||||
class Plugin(AppConfig):
|
||||
def ready(self):
|
||||
from . import main # noqa
|
||||
|
||||
return super().ready()
|
||||
|
||||
def register_api_view(self, path, name=None):
|
||||
def register(view):
|
||||
urlpatterns.append(
|
||||
urls.path(
|
||||
"plugins/{}/{}".format(self.name.replace("_", "-"), path),
|
||||
view,
|
||||
name="plugins-{}-{}".format(self.name, name),
|
||||
)
|
||||
),
|
||||
|
||||
return register
|
||||
|
||||
|
||||
def reverse(name, **kwargs):
|
||||
return urls.reverse(name, settings.PLUGINS_URLCONF, **kwargs)
|
||||
|
||||
|
||||
def resolve(name, **kwargs):
|
||||
return urls.resolve(name, settings.PLUGINS_URLCONF, **kwargs)
|
|
@ -0,0 +1,57 @@
|
|||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from django.urls import resolvers
|
||||
|
||||
from funkwhale_api.common import plugins
|
||||
|
||||
|
||||
class P(plugins.Plugin):
|
||||
name = "test_plugin"
|
||||
path = os.path.abspath(__file__)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def plugin(settings):
|
||||
yield P(app_name="test_plugin", app_module="tests.common.test_plugins.main.P")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def clear_patterns():
|
||||
plugins.urlpatterns.clear()
|
||||
resolvers._get_cached_resolver.cache_clear()
|
||||
yield
|
||||
resolvers._get_cached_resolver.cache_clear()
|
||||
|
||||
|
||||
def test_can_register_view(plugin, mocker, settings):
|
||||
view = mocker.Mock()
|
||||
plugin.register_api_view("hello", name="hello")(view)
|
||||
expected = "/plugins/test-plugin/hello"
|
||||
assert plugins.reverse("plugins-test_plugin-hello") == expected
|
||||
assert plugins.resolve(expected).func == view
|
||||
|
||||
|
||||
def test_plugin_view_middleware_not_matching(api_client, plugin, mocker, settings):
|
||||
view = mocker.Mock()
|
||||
get_response = mocker.Mock()
|
||||
middleware = plugins.PluginViewMiddleware(get_response)
|
||||
plugin.register_api_view("hello", name="hello")(view)
|
||||
request = mocker.Mock(path=plugins.reverse("plugins-test_plugin-hello"))
|
||||
response = middleware(request)
|
||||
assert response == get_response.return_value
|
||||
view.assert_not_called()
|
||||
|
||||
|
||||
def test_plugin_view_middleware_matching(api_client, plugin, mocker, settings):
|
||||
view = mocker.Mock()
|
||||
get_response = mocker.Mock(return_value=mocker.Mock(status_code=404))
|
||||
middleware = plugins.PluginViewMiddleware(get_response)
|
||||
plugin.register_api_view("hello/<slug:slug>", name="hello")(view)
|
||||
request = mocker.Mock(
|
||||
path=plugins.reverse("plugins-test_plugin-hello", kwargs={"slug": "world"})
|
||||
)
|
||||
response = middleware(request)
|
||||
assert response == view.return_value
|
||||
view.assert_called_once_with(request, slug="world")
|
Loading…
Reference in New Issue