events: add graph for event volume (#7639)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
1d003c1c0c
commit
944368c4f2
|
@ -5,7 +5,7 @@ from json import loads
|
||||||
import django_filters
|
import django_filters
|
||||||
from django.db.models.aggregates import Count
|
from django.db.models.aggregates import Count
|
||||||
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
|
from django.db.models.functions import ExtractDay, ExtractHour
|
||||||
from drf_spectacular.types import OpenApiTypes
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
||||||
from guardian.shortcuts import get_objects_for_user
|
from guardian.shortcuts import get_objects_for_user
|
||||||
|
@ -149,7 +149,15 @@ class EventViewSet(ModelViewSet):
|
||||||
return Response(EventTopPerUserSerializer(instance=events, many=True).data)
|
return Response(EventTopPerUserSerializer(instance=events, many=True).data)
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
methods=["GET"],
|
responses={200: CoordinateSerializer(many=True)},
|
||||||
|
)
|
||||||
|
@action(detail=False, methods=["GET"], pagination_class=None)
|
||||||
|
def volume(self, request: Request) -> Response:
|
||||||
|
"""Get event volume for specified filters and timeframe"""
|
||||||
|
queryset = self.filter_queryset(self.get_queryset())
|
||||||
|
return Response(queryset.get_events_per(timedelta(days=7), ExtractHour, 7 * 3))
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
responses={200: CoordinateSerializer(many=True)},
|
responses={200: CoordinateSerializer(many=True)},
|
||||||
filters=[],
|
filters=[],
|
||||||
parameters=[
|
parameters=[
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
80
schema.yml
80
schema.yml
|
@ -6276,6 +6276,86 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/GenericError'
|
$ref: '#/components/schemas/GenericError'
|
||||||
description: ''
|
description: ''
|
||||||
|
/events/events/volume/:
|
||||||
|
get:
|
||||||
|
operationId: events_events_volume_list
|
||||||
|
description: Get event volume for specified filters and timeframe
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: action
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: client_ip
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: context_authorized_app
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: Context Authorized application
|
||||||
|
- in: query
|
||||||
|
name: context_model_app
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: Context Model App
|
||||||
|
- in: query
|
||||||
|
name: context_model_name
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: Context Model Name
|
||||||
|
- in: query
|
||||||
|
name: context_model_pk
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: Context Model Primary Key
|
||||||
|
- name: ordering
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: Which field to use when ordering the results.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: search
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: A search term.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: tenant_name
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: Tenant name
|
||||||
|
- in: query
|
||||||
|
name: username
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: Username
|
||||||
|
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/notifications/:
|
/events/notifications/:
|
||||||
get:
|
get:
|
||||||
operationId: events_notifications_list
|
operationId: events_notifications_list
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import "@goauthentik/admin/events/EventVolumeChart";
|
||||||
import { EventGeo } from "@goauthentik/admin/events/utils";
|
import { EventGeo } from "@goauthentik/admin/events/utils";
|
||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||||
import { EventWithContext } from "@goauthentik/common/events";
|
import { EventWithContext } from "@goauthentik/common/events";
|
||||||
|
@ -10,7 +11,7 @@ import { TablePage } from "@goauthentik/elements/table/TablePage";
|
||||||
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
|
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
|
||||||
|
|
||||||
import { msg, str } from "@lit/localize";
|
import { msg, str } from "@lit/localize";
|
||||||
import { TemplateResult, html } from "lit";
|
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||||
import { customElement, property } from "lit/decorators.js";
|
import { customElement, property } from "lit/decorators.js";
|
||||||
|
|
||||||
import { Event, EventsApi } from "@goauthentik/api";
|
import { Event, EventsApi } from "@goauthentik/api";
|
||||||
|
@ -35,6 +36,14 @@ export class EventListPage extends TablePage<Event> {
|
||||||
@property()
|
@property()
|
||||||
order = "-created";
|
order = "-created";
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return super.styles.concat(css`
|
||||||
|
.pf-m-no-padding-bottom {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
async apiEndpoint(page: number): Promise<PaginatedResponse<Event>> {
|
async apiEndpoint(page: number): Promise<PaginatedResponse<Event>> {
|
||||||
return new EventsApi(DEFAULT_CONFIG).eventsEventsList({
|
return new EventsApi(DEFAULT_CONFIG).eventsEventsList({
|
||||||
ordering: this.order,
|
ordering: this.order,
|
||||||
|
@ -55,6 +64,19 @@ export class EventListPage extends TablePage<Event> {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderSectionBefore(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="pf-c-page__main-section pf-m-no-padding-bottom">
|
||||||
|
<ak-events-volume-chart
|
||||||
|
.query=${{
|
||||||
|
page: this.page,
|
||||||
|
search: this.search,
|
||||||
|
}}
|
||||||
|
></ak-events-volume-chart>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
row(item: EventWithContext): TemplateResult[] {
|
row(item: EventWithContext): TemplateResult[] {
|
||||||
return [
|
return [
|
||||||
html`<div>${actionToLabel(item.action)}</div>
|
html`<div>${actionToLabel(item.action)}</div>
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
import { DEFAULT_CONFIG } from "@goauthentik/app/common/api/config";
|
||||||
|
import { AKChart } from "@goauthentik/app/elements/charts/Chart";
|
||||||
|
import { ChartData } from "chart.js";
|
||||||
|
|
||||||
|
import { msg } from "@lit/localize";
|
||||||
|
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators.js";
|
||||||
|
|
||||||
|
import PFCard from "@patternfly/patternfly/components/Card/card.css";
|
||||||
|
|
||||||
|
import { Coordinate, EventsApi, EventsEventsListRequest } from "@goauthentik/api";
|
||||||
|
|
||||||
|
@customElement("ak-events-volume-chart")
|
||||||
|
export class EventVolumeChart extends AKChart<Coordinate[]> {
|
||||||
|
_query?: EventsEventsListRequest;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
set query(value: EventsEventsListRequest | undefined) {
|
||||||
|
this._query = value;
|
||||||
|
this.refreshHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return super.styles.concat(
|
||||||
|
PFCard,
|
||||||
|
css`
|
||||||
|
.pf-c-card__body {
|
||||||
|
height: 12rem;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
apiRequest(): Promise<Coordinate[]> {
|
||||||
|
return new EventsApi(DEFAULT_CONFIG).eventsEventsVolumeList(this._query);
|
||||||
|
}
|
||||||
|
|
||||||
|
getChartData(data: Coordinate[]): ChartData {
|
||||||
|
return {
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: msg("Events"),
|
||||||
|
backgroundColor: "rgba(189, 229, 184, .5)",
|
||||||
|
spanGaps: true,
|
||||||
|
data:
|
||||||
|
data.map((cord) => {
|
||||||
|
return {
|
||||||
|
x: cord.xCord || 0,
|
||||||
|
y: cord.yCord || 0,
|
||||||
|
};
|
||||||
|
}) || [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): TemplateResult {
|
||||||
|
return html`<div class="pf-c-card">
|
||||||
|
<div class="pf-c-card__title">${msg("Event volume")}</div>
|
||||||
|
<div class="pf-c-card__body">${super.render()}</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6114,6 +6114,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sd7728d2b6e1d25e9">
|
<trans-unit id="sd7728d2b6e1d25e9">
|
||||||
<source>Property mappings used for group creation.</source>
|
<source>Property mappings used for group creation.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s7513372fe60f6387">
|
||||||
|
<source>Event volume</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
@ -6391,6 +6391,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sd7728d2b6e1d25e9">
|
<trans-unit id="sd7728d2b6e1d25e9">
|
||||||
<source>Property mappings used for group creation.</source>
|
<source>Property mappings used for group creation.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s7513372fe60f6387">
|
||||||
|
<source>Event volume</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
@ -6030,6 +6030,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sd7728d2b6e1d25e9">
|
<trans-unit id="sd7728d2b6e1d25e9">
|
||||||
<source>Property mappings used for group creation.</source>
|
<source>Property mappings used for group creation.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s7513372fe60f6387">
|
||||||
|
<source>Event volume</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
@ -8023,6 +8023,9 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sd7728d2b6e1d25e9">
|
<trans-unit id="sd7728d2b6e1d25e9">
|
||||||
<source>Property mappings used for group creation.</source>
|
<source>Property mappings used for group creation.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s7513372fe60f6387">
|
||||||
|
<source>Event volume</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
@ -6238,6 +6238,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sd7728d2b6e1d25e9">
|
<trans-unit id="sd7728d2b6e1d25e9">
|
||||||
<source>Property mappings used for group creation.</source>
|
<source>Property mappings used for group creation.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s7513372fe60f6387">
|
||||||
|
<source>Event volume</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
@ -7978,4 +7978,7 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||||
<source>Property mappings used for group creation.</source>
|
<source>Property mappings used for group creation.</source>
|
||||||
<target>Ƥŕōƥēŕţŷ màƥƥĩńĝś ũśēď ƒōŕ ĝŕōũƥ ćŕēàţĩōń.</target>
|
<target>Ƥŕōƥēŕţŷ màƥƥĩńĝś ũśēď ƒōŕ ĝŕōũƥ ćŕēàţĩōń.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="s7513372fe60f6387">
|
||||||
|
<source>Event volume</source>
|
||||||
|
</trans-unit>
|
||||||
</body></file></xliff>
|
</body></file></xliff>
|
||||||
|
|
|
@ -6023,6 +6023,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sd7728d2b6e1d25e9">
|
<trans-unit id="sd7728d2b6e1d25e9">
|
||||||
<source>Property mappings used for group creation.</source>
|
<source>Property mappings used for group creation.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s7513372fe60f6387">
|
||||||
|
<source>Event volume</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
@ -8025,6 +8025,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sd7728d2b6e1d25e9">
|
<trans-unit id="sd7728d2b6e1d25e9">
|
||||||
<source>Property mappings used for group creation.</source>
|
<source>Property mappings used for group creation.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s7513372fe60f6387">
|
||||||
|
<source>Event volume</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
@ -6071,6 +6071,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sd7728d2b6e1d25e9">
|
<trans-unit id="sd7728d2b6e1d25e9">
|
||||||
<source>Property mappings used for group creation.</source>
|
<source>Property mappings used for group creation.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s7513372fe60f6387">
|
||||||
|
<source>Event volume</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
@ -7962,6 +7962,9 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="sd7728d2b6e1d25e9">
|
<trans-unit id="sd7728d2b6e1d25e9">
|
||||||
<source>Property mappings used for group creation.</source>
|
<source>Property mappings used for group creation.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="s7513372fe60f6387">
|
||||||
|
<source>Event volume</source>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|
Reference in New Issue