From c66ad75f5905259b5966dee40880acb054d89513 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 18 Jun 2024 13:13:22 +0200 Subject: [PATCH] feat: enable v1 root drf browsable Signed-off-by: Alex --- docs/deployment.md | 2 + src/aap_eda/api/urls.py | 65 ++++++++++++++----- src/aap_eda/api/views/__init__.py | 4 +- src/aap_eda/api/views/root.py | 53 +++++++++++++++ src/aap_eda/settings/default.py | 1 + tests/integration/api/test_v1_root.py | 60 +++++++++++++++++ .../docker/docker-compose-dev-redis-tls.yaml | 3 +- tools/docker/docker-compose-dev.yaml | 3 +- tools/docker/docker-compose-mac.yml | 3 +- tools/docker/docker-compose-stage.yaml | 3 +- 10 files changed, 174 insertions(+), 23 deletions(-) create mode 100644 src/aap_eda/api/views/root.py create mode 100644 tests/integration/api/test_v1_root.py diff --git a/docs/deployment.md b/docs/deployment.md index 39836644a..7852f121a 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -123,3 +123,5 @@ Minikube is the recommended method for macOS users **Note**: For fedora, the binary may be `go-task`. You can now access the UI at using the above credentials. +Also you can inspect the API documentation at +or navigate through the resources with the DRF browsable API at diff --git a/src/aap_eda/api/urls.py b/src/aap_eda/api/urls.py index 7f80fa23e..9fd0efb90 100644 --- a/src/aap_eda/api/urls.py +++ b/src/aap_eda/api/urls.py @@ -34,27 +34,47 @@ router = routers.SimpleRouter() # basename has to be set when queryset is user-dependent # which is any model with permissions -router.register("projects", views.ProjectViewSet) -router.register("rulebooks", views.RulebookViewSet) -router.register("activations", views.ActivationViewSet) +router.register("projects", views.ProjectViewSet, basename="projects") +router.register("rulebooks", views.RulebookViewSet, basename="rulebooks") +router.register("activations", views.ActivationViewSet, basename="activations") router.register( "activation-instances", views.ActivationInstanceViewSet, - basename="activationinstance", + basename="activation-instances", +) +router.register("audit-rules", views.AuditRuleViewSet, basename="audit-rules") +router.register("users", views.UserViewSet, basename="users") +router.register( + "event-streams", + views.EventStreamViewSet, + basename="event-streams", ) -router.register("audit-rules", views.AuditRuleViewSet) -router.register("users", views.UserViewSet) -router.register("event-streams", views.EventStreamViewSet) router.register( "users/me/awx-tokens", views.CurrentUserAwxTokenViewSet, - basename="controller-token", + basename="awx-tokens", +) +router.register( + "credential-types", + views.CredentialTypeViewSet, + basename="credential-types", +) +router.register( + "eda-credentials", + views.EdaCredentialViewSet, + basename="eda-credentials", +) +router.register( + "decision-environments", + views.DecisionEnvironmentViewSet, + basename="decision-environments", +) +router.register( + "organizations", + views.OrganizationViewSet, + basename="organizations", ) -router.register("credential-types", views.CredentialTypeViewSet) -router.register("eda-credentials", views.EdaCredentialViewSet) -router.register("decision-environments", views.DecisionEnvironmentViewSet) -router.register("organizations", views.OrganizationViewSet) -router.register("teams", views.TeamViewSet) +router.register("teams", views.TeamViewSet, basename="teams") openapi_urls = [ path( @@ -80,21 +100,30 @@ ] v1_urls = [ - path("status/", core_views.StatusView.as_view()), + path("status/", core_views.StatusView.as_view(), name="status"), path("", include(dab_urls)), path("", include(resource_api_urls)), path("", include(openapi_urls)), - path("auth/session/login/", views.SessionLoginView.as_view()), - path("auth/session/logout/", views.SessionLogoutView.as_view()), + path( + "auth/session/login/", + views.SessionLoginView.as_view(), + name="session-login", + ), + path( + "auth/session/logout/", + views.SessionLogoutView.as_view(), + name="session-logout", + ), path( "auth/token/refresh/", jwt_views.TokenRefreshView.as_view(), - name="token_refresh", + name="token-refresh", ), - path("users/me/", views.CurrentUserView.as_view()), + path("users/me/", views.CurrentUserView.as_view(), name="current-user"), *router.urls, ] urlpatterns = [ + path("v1/", views.ApiV1RootView.as_view()), path("v1/", include(v1_urls)), ] diff --git a/src/aap_eda/api/views/__init__.py b/src/aap_eda/api/views/__init__.py index 0c5edd6c8..8d94c5376 100644 --- a/src/aap_eda/api/views/__init__.py +++ b/src/aap_eda/api/views/__init__.py @@ -20,6 +20,7 @@ from .event_stream import EventStreamViewSet from .organization import OrganizationViewSet from .project import ProjectViewSet +from .root import ApiV1RootView from .rulebook import AuditRuleViewSet, RulebookViewSet from .team import TeamViewSet from .user import CurrentUserAwxTokenViewSet, CurrentUserView, UserViewSet @@ -28,7 +29,6 @@ # auth "SessionLoginView", "SessionLogoutView", - "RoleViewSet", # project "ProjectViewSet", "AuditRuleViewSet", @@ -51,4 +51,6 @@ "OrganizationViewSet", # teams "TeamViewSet", + # root + "ApiV1RootView", ) diff --git a/src/aap_eda/api/views/root.py b/src/aap_eda/api/views/root.py new file mode 100644 index 000000000..f7864659a --- /dev/null +++ b/src/aap_eda/api/views/root.py @@ -0,0 +1,53 @@ +# Copyright 2024 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import logging + +from django.urls import URLPattern, URLResolver +from rest_framework.response import Response +from rest_framework.reverse import reverse +from rest_framework.views import APIView + +LOGGER = logging.getLogger(__name__) + + +class ApiV1RootView(APIView): + def get(self, request, *args, **kwargs): + urls = get_api_v1_urls(request=request) + return Response(urls) + + +def get_api_v1_urls(request=None): + from aap_eda.api.urls import v1_urls + + def list_urls(urls): + url_list = {} + for url in urls: + if isinstance(url, URLResolver): + url_list.update(list_urls(url.url_patterns)) + elif isinstance(url, URLPattern): + name = url.name + if not name: + LOGGER.warning( + "URL %s has no name, DRF browsable API will omit it", + url.pattern, + ) + continue + if url.pattern.regex.groups: + continue + url_list[name] = reverse(name, request=request) + return url_list + + return list_urls(v1_urls) diff --git a/src/aap_eda/settings/default.py b/src/aap_eda/settings/default.py index 1ce9c5f00..5249e29a5 100644 --- a/src/aap_eda/settings/default.py +++ b/src/aap_eda/settings/default.py @@ -302,6 +302,7 @@ def _get_databases_settings() -> dict: # https://docs.djangoproject.com/en/4.1/howto/static-files/ STATIC_URL = "static/" +STATIC_ROOT = settings.get("STATIC_ROOT", "/var/lib/eda/static") MEDIA_ROOT = settings.get("MEDIA_ROOT", "/var/lib/eda/files") diff --git a/tests/integration/api/test_v1_root.py b/tests/integration/api/test_v1_root.py new file mode 100644 index 000000000..db2c9ff3e --- /dev/null +++ b/tests/integration/api/test_v1_root.py @@ -0,0 +1,60 @@ +# Copyright 2024 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pytest + +from tests.integration.constants import api_url_v1 + + +@pytest.mark.django_db +def test_v1_root(admin_client): + expected_slugs = [ + "/status/", + "/role_definitions/", + "/role_user_assignments/", + "/role_team_assignments/", + "/role_metadata/", + "/service-index/metadata/", + "/service-index/validate-local-account/", + "/service-index/resources/", + "/service-index/resource-types/", + "/service-index/", + "/openapi.json", + "/openapi.yaml", + "/docs", + "/redoc", + "/auth/session/login/", + "/auth/session/logout/", + "/auth/token/refresh/", + "/users/me/", + "/projects/", + "/rulebooks/", + "/activations/", + "/activation-instances/", + "/audit-rules/", + "/users/", + "/event-streams/", + "/users/me/awx-tokens/", + "/credential-types/", + "/eda-credentials/", + "/decision-environments/", + "/organizations/", + "/teams/", + ] + + response = admin_client.get(f"{api_url_v1}/") + assert response.status_code == 200 + for slug in expected_slugs: + assert any( + slug in url for url in response.data.values() + ), f"Expected slug {slug} not found in response" diff --git a/tools/docker/docker-compose-dev-redis-tls.yaml b/tools/docker/docker-compose-dev-redis-tls.yaml index cc36a7e2c..442ea0782 100644 --- a/tools/docker/docker-compose-dev-redis-tls.yaml +++ b/tools/docker/docker-compose-dev-redis-tls.yaml @@ -84,7 +84,8 @@ services: - /bin/bash - -c - >- - aap-eda-manage migrate + aap-eda-manage collectstatic --noinput + && aap-eda-manage migrate && aap-eda-manage create_initial_data && scripts/create_superuser.sh && aap-eda-manage runserver 0.0.0.0:8000 diff --git a/tools/docker/docker-compose-dev.yaml b/tools/docker/docker-compose-dev.yaml index 69c078249..a6536260d 100644 --- a/tools/docker/docker-compose-dev.yaml +++ b/tools/docker/docker-compose-dev.yaml @@ -100,7 +100,8 @@ services: - /bin/bash - -c - >- - aap-eda-manage migrate + aap-eda-manage collectstatic --noinput + && aap-eda-manage migrate && aap-eda-manage create_initial_data && scripts/create_superuser.sh && aap-eda-manage runserver 0.0.0.0:8000 diff --git a/tools/docker/docker-compose-mac.yml b/tools/docker/docker-compose-mac.yml index 44f8c9465..03cb9085d 100644 --- a/tools/docker/docker-compose-mac.yml +++ b/tools/docker/docker-compose-mac.yml @@ -54,7 +54,8 @@ services: - /bin/bash - -c - >- - aap-eda-manage migrate + aap-eda-manage collectstatic --noinput + && aap-eda-manage migrate && aap-eda-manage create_initial_data && scripts/create_superuser.sh && aap-eda-manage runserver 0.0.0.0:8000 diff --git a/tools/docker/docker-compose-stage.yaml b/tools/docker/docker-compose-stage.yaml index a76f0abde..e25e9a00b 100644 --- a/tools/docker/docker-compose-stage.yaml +++ b/tools/docker/docker-compose-stage.yaml @@ -70,7 +70,8 @@ services: - /bin/bash - -c - >- - aap-eda-manage migrate + aap-eda-manage collectstatic --noinput + && aap-eda-manage migrate && aap-eda-manage create_initial_data && scripts/create_superuser.sh && gunicorn -b 0.0.0.0:8000