diff --git a/authentik/admin/api/metrics.py b/authentik/admin/api/metrics.py index 1a917115f1..f384d40dbd 100644 --- a/authentik/admin/api/metrics.py +++ b/authentik/admin/api/metrics.py @@ -1,6 +1,5 @@ """authentik administration metrics""" - from rest_framework.fields import IntegerField from authentik.core.api.utils import PassiveSerializer diff --git a/authentik/core/api/applications.py b/authentik/core/api/applications.py index c96680d373..269b82d2db 100644 --- a/authentik/core/api/applications.py +++ b/authentik/core/api/applications.py @@ -2,11 +2,9 @@ from collections.abc import Iterator from copy import copy -from datetime import timedelta from django.core.cache import cache from django.db.models import QuerySet -from django.db.models.functions import ExtractHour from django.shortcuts import get_object_or_404 from drf_spectacular.types import OpenApiTypes from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema @@ -20,7 +18,6 @@ from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet from structlog.stdlib import get_logger -from authentik.admin.api.metrics import CoordinateSerializer from authentik.api.pagination import Pagination from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT from authentik.core.api.providers import ProviderSerializer @@ -28,7 +25,6 @@ from authentik.core.api.used_by import UsedByMixin from authentik.core.api.utils import ModelSerializer from authentik.core.models import Application, User from authentik.events.logs import LogEventSerializer, capture_logs -from authentik.events.models import EventAction from authentik.lib.utils.file import ( FilePathSerializer, FileUploadSerializer, @@ -321,18 +317,3 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet): """Set application icon (as URL)""" app: Application = self.get_object() return set_file_url(request, app, "meta_icon") - - @permission_required("authentik_core.view_application", ["authentik_events.view_event"]) - @extend_schema(responses={200: CoordinateSerializer(many=True)}) - @action(detail=True, pagination_class=None, filter_backends=[]) - def metrics(self, request: Request, slug: str): - """Metrics for application logins""" - app = self.get_object() - return Response( - get_objects_for_user(request.user, "authentik_events.view_event").filter( - action=EventAction.AUTHORIZE_APPLICATION, - context__authorized_application__pk=app.pk.hex, - ) - # 3 data points per day, so 8 hour spans - .get_events_per(timedelta(days=7), ExtractHour, 7 * 3) - ) diff --git a/pyproject.toml b/pyproject.toml index 17f713b283..016688a7f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -140,6 +140,7 @@ skip = [ "**/storybook-static", "**/web/src/locales", "**/web/xliff", + "**/web/out", "./web/storybook-static", "./web/custom-elements.json", "./website/build", diff --git a/web/src/admin/applications/ApplicationAuthorizeChart.ts b/web/src/admin/applications/ApplicationAuthorizeChart.ts index 0d1b8ac7b2..1d21130e37 100644 --- a/web/src/admin/applications/ApplicationAuthorizeChart.ts +++ b/web/src/admin/applications/ApplicationAuthorizeChart.ts @@ -1,47 +1,38 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { AKChart } from "@goauthentik/elements/charts/Chart"; -import { ChartData, Tick } from "chart.js"; +import { ChartData } from "chart.js"; -import { msg, str } from "@lit/localize"; +import { msg } from "@lit/localize"; import { customElement, property } from "lit/decorators.js"; -import { Coordinate, CoreApi } from "@goauthentik/api"; +import { EventActions, EventVolume, EventsApi } from "@goauthentik/api"; @customElement("ak-charts-application-authorize") -export class ApplicationAuthorizeChart extends AKChart { - @property() - applicationSlug!: string; +export class ApplicationAuthorizeChart extends AKChart { + @property({ attribute: "application-id" }) + applicationId!: string; - async apiRequest(): Promise { - return new CoreApi(DEFAULT_CONFIG).coreApplicationsMetricsList({ - slug: this.applicationSlug, + async apiRequest(): Promise { + return new EventsApi(DEFAULT_CONFIG).eventsEventsVolumeList({ + action: EventActions.AuthorizeApplication, + contextAuthorizedApp: this.applicationId.replaceAll("-", ""), }); } - timeTickCallback(tickValue: string | number, index: number, ticks: Tick[]): string { - const valueStamp = ticks[index]; - const delta = Date.now() - valueStamp.value; - const ago = Math.round(delta / 1000 / 3600 / 24); - return msg(str`${ago} days ago`); - } - - getChartData(data: Coordinate[]): ChartData { - return { - datasets: [ - { - label: msg("Authorizations"), - backgroundColor: "rgba(189, 229, 184, .5)", - spanGaps: true, - data: - data.map((cord) => { - return { - x: cord.xCord || 0, - y: cord.yCord || 0, - }; - }) || [], - }, - ], - }; + getChartData(data: EventVolume[]): ChartData { + return this.eventVolume( + data, + new Map([ + [ + EventActions.AuthorizeApplication, + { + label: msg("Authorizations"), + backgroundColor: "rgba(189, 229, 184, .5)", + spanGaps: true, + }, + ], + ]), + ); } } diff --git a/web/src/admin/applications/ApplicationViewPage.ts b/web/src/admin/applications/ApplicationViewPage.ts index 1de763df35..bf1a2bd383 100644 --- a/web/src/admin/applications/ApplicationViewPage.ts +++ b/web/src/admin/applications/ApplicationViewPage.ts @@ -283,7 +283,7 @@ export class ApplicationViewPage extends AKElement {
${this.application && html` `}