the rest of the owl

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens Langhammer
2025-06-06 03:44:29 +02:00
parent 24f852b8d8
commit 41f5d42ba9
6 changed files with 32 additions and 134 deletions

View File

@ -1,12 +0,0 @@
"""authentik administration metrics"""
from rest_framework.fields import IntegerField
from authentik.core.api.utils import PassiveSerializer
class CoordinateSerializer(PassiveSerializer):
"""Coordinates for diagrams"""
x_cord = IntegerField(read_only=True)
y_cord = IntegerField(read_only=True)

View File

@ -1,12 +1,11 @@
"""Events API Views""" """Events API Views"""
from datetime import timedelta from datetime import timedelta
from json import loads
import django_filters import django_filters
from django.db.models import Count, QuerySet from django.db.models import Count, QuerySet
from django.db.models.fields.json import KeyTextTransform, KeyTransform from django.db.models.fields.json import KeyTextTransform, KeyTransform
from django.db.models.functions import ExtractDay, TruncDate from django.db.models.functions import TruncDate
from django.db.models.query_utils import Q from django.db.models.query_utils import Q
from django.utils.timezone import now from django.utils.timezone import now
from drf_spectacular.types import OpenApiTypes from drf_spectacular.types import OpenApiTypes
@ -18,7 +17,6 @@ from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.admin.api.metrics import CoordinateSerializer
from authentik.core.api.object_types import TypeCreateSerializer from authentik.core.api.object_types import TypeCreateSerializer
from authentik.core.api.utils import ModelSerializer, PassiveSerializer from authentik.core.api.utils import ModelSerializer, PassiveSerializer
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
@ -199,39 +197,6 @@ class EventViewSet(ModelViewSet):
.order_by("-day", "action") .order_by("-day", "action")
) )
@extend_schema(
responses={200: CoordinateSerializer(many=True)},
filters=[],
parameters=[
OpenApiParameter(
"action",
type=OpenApiTypes.STR,
location=OpenApiParameter.QUERY,
required=False,
),
OpenApiParameter(
"query",
type=OpenApiTypes.STR,
location=OpenApiParameter.QUERY,
required=False,
),
],
)
@action(detail=False, methods=["GET"], pagination_class=None)
def per_month(self, request: Request):
"""Get the count of events per month"""
filtered_action = request.query_params.get("action", EventAction.LOGIN)
try:
query = loads(request.query_params.get("query", "{}"))
except ValueError:
return Response(status=400)
return Response(
get_objects_for_user(request.user, "authentik_events.view_event")
.filter(action=filtered_action)
.filter(**query)
.get_events_per(timedelta(weeks=4), ExtractDay, 30)
)
@extend_schema(responses={200: TypeCreateSerializer(many=True)}) @extend_schema(responses={200: TypeCreateSerializer(many=True)})
@action(detail=False, pagination_class=None, filter_backends=[]) @action(detail=False, pagination_class=None, filter_backends=[])
def actions(self, request: Request) -> Response: def actions(self, request: Request) -> Response:

View File

@ -7337,44 +7337,6 @@ paths:
schema: schema:
$ref: '#/components/schemas/GenericError' $ref: '#/components/schemas/GenericError'
description: '' description: ''
/events/events/per_month/:
get:
operationId: events_events_per_month_list
description: Get the count of events per month
parameters:
- in: query
name: action
schema:
type: string
- in: query
name: query
schema:
type: string
tags:
- events
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Coordinate'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/events/events/top_per_user/: /events/events/top_per_user/:
get: get:
operationId: events_events_top_per_user_list operationId: events_events_top_per_user_list
@ -43576,19 +43538,6 @@ components:
- sidebar_left - sidebar_left
- sidebar_right - sidebar_right
type: string type: string
Coordinate:
type: object
description: Coordinates for diagrams
properties:
x_cord:
type: integer
readOnly: true
y_cord:
type: integer
readOnly: true
required:
- x_cord
- y_cord
CountryCodeEnum: CountryCodeEnum:
enum: enum:
- AF - AF

View File

@ -13,7 +13,7 @@ import PFList from "@patternfly/patternfly/components/List/list.css";
import PFPage from "@patternfly/patternfly/components/Page/page.css"; import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css"; import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";
import { EventActions } from "@goauthentik/api"; import { EventActions, EventsEventsVolumeListRequest } from "@goauthentik/api";
@customElement("ak-admin-dashboard-users") @customElement("ak-admin-dashboard-users")
export class DashboardUserPage extends AKElement { export class DashboardUserPage extends AKElement {
@ -46,9 +46,9 @@ export class DashboardUserPage extends AKElement {
<ak-aggregate-card header=${msg("Users created per day in the last month")}> <ak-aggregate-card header=${msg("Users created per day in the last month")}>
<ak-charts-admin-model-per-day <ak-charts-admin-model-per-day
.query=${{ .query=${{
context__model__app: "authentik_core", contextModelApp: "authentik_core",
context__model__model_name: "user", contextModelName: "user",
}} } as EventsEventsVolumeListRequest}
label=${msg("Users created")} label=${msg("Users created")}
> >
</ak-charts-admin-model-per-day> </ak-charts-admin-model-per-day>

View File

@ -5,10 +5,16 @@ import { ChartData, Tick } from "chart.js";
import { msg, str } from "@lit/localize"; import { msg, str } from "@lit/localize";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import { Coordinate, EventActions, EventsApi } from "@goauthentik/api"; import {
Coordinate,
EventActions,
EventVolume,
EventsApi,
EventsEventsVolumeListRequest,
} from "@goauthentik/api";
@customElement("ak-charts-admin-model-per-day") @customElement("ak-charts-admin-model-per-day")
export class AdminModelPerDay extends AKChart<Coordinate[]> { export class AdminModelPerDay extends AKChart<EventVolume[]> {
@property() @property()
action: EventActions = EventActions.ModelCreated; action: EventActions = EventActions.ModelCreated;
@ -16,39 +22,29 @@ export class AdminModelPerDay extends AKChart<Coordinate[]> {
label?: string; label?: string;
@property({ attribute: false }) @property({ attribute: false })
query?: { [key: string]: unknown } | undefined; query?: EventsEventsVolumeListRequest;
async apiRequest(): Promise<Coordinate[]> { async apiRequest(): Promise<EventVolume[]> {
return new EventsApi(DEFAULT_CONFIG).eventsEventsPerMonthList({ return new EventsApi(DEFAULT_CONFIG).eventsEventsVolumeList({
action: this.action, action: this.action,
query: JSON.stringify(this.query || {}), ...this.query,
}); });
} }
timeTickCallback(tickValue: string | number, index: number, ticks: Tick[]): string { getChartData(data: EventVolume[]): ChartData {
const valueStamp = ticks[index]; return this.eventVolume(
const delta = Date.now() - valueStamp.value; data,
const ago = Math.round(delta / 1000 / 3600 / 24); new Map([
return msg(str`${ago} days ago`); [
} this.action,
getChartData(data: Coordinate[]): ChartData {
return {
datasets: [
{ {
label: this.label || msg("Objects created"), label: this.label || msg("Objects created"),
backgroundColor: "rgba(189, 229, 184, .5)", backgroundColor: "rgba(189, 229, 184, .5)",
spanGaps: true, spanGaps: true,
data:
data.map((cord) => {
return {
x: cord.xCord || 0,
y: cord.yCord || 0,
};
}) || [],
}, },
], ],
}; ]),
);
} }
} }

View File

@ -33,7 +33,7 @@ export class EventVolumeChart extends AKChart<EventVolume[]> {
apiRequest(): Promise<EventVolume[]> { apiRequest(): Promise<EventVolume[]> {
return new EventsApi(DEFAULT_CONFIG).eventsEventsVolumeList({ return new EventsApi(DEFAULT_CONFIG).eventsEventsVolumeList({
historyDays: 14, historyDays: 14,
...this._query ...this._query,
}); });
} }