diff --git a/passbook/admin/api/__init__.py b/passbook/admin/api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/passbook/admin/api/overview.py b/passbook/admin/api/overview.py new file mode 100644 index 000000000..ef8d42b51 --- /dev/null +++ b/passbook/admin/api/overview.py @@ -0,0 +1,80 @@ +"""passbook administration overview""" +from django.core.cache import cache +from django.http import response +from drf_yasg.utils import swagger_auto_schema +from rest_framework.fields import SerializerMethodField +from rest_framework.permissions import IsAdminUser +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.serializers import Serializer +from rest_framework.viewsets import ViewSet + +from passbook import __version__ +from passbook.admin.tasks import VERSION_CACHE_KEY, update_latest_version +from passbook.core.models import Provider +from passbook.policies.models import Policy +from passbook.root.celery import CELERY_APP + + +class AdministrationOverviewSerializer(Serializer): + """Overview View""" + + version = SerializerMethodField() + version_latest = SerializerMethodField() + worker_count = SerializerMethodField() + providers_without_application = SerializerMethodField() + policies_without_binding = SerializerMethodField() + cached_policies = SerializerMethodField() + cached_flows = SerializerMethodField() + + def get_version(self, _) -> str: + """Get current version""" + return __version__ + + def get_version_latest(self, _) -> str: + """Get latest version from cache""" + version_in_cache = cache.get(VERSION_CACHE_KEY) + if not version_in_cache: + update_latest_version.delay() + return __version__ + return version_in_cache + + def get_worker_count(self, _) -> int: + """Ping workers""" + return len(CELERY_APP.control.ping(timeout=0.5)) + + def get_providers_without_application(self, _) -> int: + """Count of providers without application""" + return len(Provider.objects.filter(application=None)) + + def get_policies_without_binding(self, _) -> int: + """Count of policies not bound or use in prompt stages""" + return len( + Policy.objects.filter(bindings__isnull=True, promptstage__isnull=True) + ) + + def get_cached_policies(self, _) -> int: + """Get cached policy count""" + return len(cache.keys("policy_*")) + + def get_cached_flows(self, _) -> int: + """Get cached flow count""" + return len(cache.keys("flow_*")) + + def create(self, request: Request) -> response: + raise NotImplementedError + + def update(self, request: Request) -> Response: + raise NotImplementedError + + +class AdministrationOverviewViewSet(ViewSet): + """Return single instance of AdministrationOverviewSerializer""" + + permission_classes = [IsAdminUser] + + @swagger_auto_schema(responses={200: AdministrationOverviewSerializer(many=True)}) + def list(self, request: Request) -> Response: + """Return single instance of AdministrationOverviewSerializer""" + serializer = AdministrationOverviewSerializer(True) + return Response(serializer.data) diff --git a/passbook/admin/templates/administration/base.html b/passbook/admin/templates/administration/base.html index 7b09fdeb1..c5213a97f 100644 --- a/passbook/admin/templates/administration/base.html +++ b/passbook/admin/templates/administration/base.html @@ -25,7 +25,7 @@
  • - {% trans 'System Status' %} + {% trans 'Overview' %}
  • diff --git a/passbook/admin/views/overview.py b/passbook/admin/views/overview.py index d2c66ca96..0941eeaf4 100644 --- a/passbook/admin/views/overview.py +++ b/passbook/admin/views/overview.py @@ -1,6 +1,7 @@ """passbook administration overview""" from typing import Union +from django.conf import settings from django.core.cache import cache from django.shortcuts import redirect, reverse from django.views.generic import TemplateView @@ -32,7 +33,8 @@ class AdministrationOverviewView(AdminRequiredMixin, TemplateView): """Get latest version from cache""" version_in_cache = cache.get(VERSION_CACHE_KEY) if not version_in_cache: - update_latest_version.delay() + if not settings.DEBUG: + update_latest_version.delay() return parse(__version__) return parse(version_in_cache) diff --git a/passbook/api/v2/urls.py b/passbook/api/v2/urls.py index 49503cced..b0d1d5a53 100644 --- a/passbook/api/v2/urls.py +++ b/passbook/api/v2/urls.py @@ -4,6 +4,7 @@ from drf_yasg import openapi from drf_yasg.views import get_schema_view from rest_framework import routers +from passbook.admin.api.overview import AdministrationOverviewViewSet from passbook.api.permissions import CustomObjectPermissions from passbook.api.v2.messages import MessagesViewSet from passbook.audit.api import EventViewSet @@ -51,6 +52,10 @@ router = routers.DefaultRouter() router.register("root/messages", MessagesViewSet, basename="messages") +router.register( + "admin/overview", AdministrationOverviewViewSet, basename="admin_overview" +) + router.register("core/applications", ApplicationViewSet) router.register("core/groups", GroupViewSet) router.register("core/users", UserViewSet) diff --git a/swagger.yaml b/swagger.yaml index 56483228f..f6348ca0a 100755 --- a/swagger.yaml +++ b/swagger.yaml @@ -19,6 +19,21 @@ securityDefinitions: security: - token: [] paths: + /admin/overview/: + get: + operationId: admin_overview_list + description: Return single instance of AdministrationOverviewSerializer + parameters: [] + responses: + '200': + description: '' + schema: + type: array + items: + $ref: '#/definitions/AdministrationOverview' + tags: + - admin + parameters: [] /audit/events/: get: operationId: audit_events_list @@ -5943,6 +5958,37 @@ paths: type: string format: uuid definitions: + AdministrationOverview: + type: object + properties: + version: + title: Version + type: string + readOnly: true + version_latest: + title: Version latest + type: string + readOnly: true + worker_count: + title: Worker count + type: integer + readOnly: true + providers_without_application: + title: Providers without application + type: integer + readOnly: true + policies_without_binding: + title: Policies without binding + type: integer + readOnly: true + cached_policies: + title: Cached policies + type: integer + readOnly: true + cached_flows: + title: Cached flows + type: integer + readOnly: true Event: required: - action