This is an automated email from the ASF dual-hosted git repository.
pierrejeambrun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 2f5fb76d467 Add `get_display_name` to `BaseUser` interface (#70583)
2f5fb76d467 is described below
commit 2f5fb76d467b8cb84b4ebdd11058df7060fb41cc
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Tue Jul 28 14:02:43 2026 +0200
Add `get_display_name` to `BaseUser` interface (#70583)
* Show user display name in the audit log via get_display_name
The audit log's owner_display_name always equalled owner because the action
logger stored get_name() in both fields. Add a get_display_name() to the
auth
manager user model, defaulting to get_name() so auth managers written
before it
keep working unchanged, and have the FAB user return its full name. The
action
logger now records get_display_name() as owner_display_name, so the audit
log
can show a friendlier name than the raw owner identifier where one exists.
Follow-up to #68833.
* Add an owner display name filter to the audit log
The audit log user column now shows owner_display_name, so its filter should
match that value. Add server-side pattern and prefix-pattern search params
on
owner_display_name and point the existing User filter at them, and drop the
redundant UI owner fallback so the displayed value and the filter stay in
sync.
* Use spec on the mocked request and session in the decorator test
* Use a real request instead of a mock in the decorator test
A real Request built from a minimal ASGI scope supplies genuine empty
headers/query/path params, so nothing needs stubbing and the test cannot
drift
from the real request interface. The session stays a spec'd mock to capture
the
logged row.
---
.../api_fastapi/auth/managers/models/base_user.py | 9 +++++++
.../core_api/openapi/v2-rest-api-generated.yaml | 26 ++++++++++++++++++
.../core_api/routes/public/event_logs.py | 10 +++++++
.../src/airflow/api_fastapi/logging/decorators.py | 2 +-
.../src/airflow/ui/openapi-gen/queries/common.ts | 6 +++--
.../ui/openapi-gen/queries/ensureQueryData.ts | 8 ++++--
.../src/airflow/ui/openapi-gen/queries/prefetch.ts | 8 ++++--
.../src/airflow/ui/openapi-gen/queries/queries.ts | 8 ++++--
.../src/airflow/ui/openapi-gen/queries/suspense.ts | 8 ++++--
.../ui/openapi-gen/requests/services.gen.ts | 4 +++
.../airflow/ui/openapi-gen/requests/types.gen.ts | 8 ++++++
.../src/airflow/ui/src/pages/Events/Events.tsx | 6 ++---
.../api_fastapi/auth/managers/models/__init__.py} | 14 ----------
.../auth/managers/models/test_base_user.py} | 19 +++++++------
.../core_api/routes/public/test_event_logs.py | 14 ++++++++++
.../unit/api_fastapi/logging/test_decorators.py | 31 ++++++++++++++++++++++
.../providers/fab/auth_manager/models/__init__.py | 3 +++
.../fab/auth_manager/models/test_user_model.py | 7 +++++
18 files changed, 155 insertions(+), 36 deletions(-)
diff --git
a/airflow-core/src/airflow/api_fastapi/auth/managers/models/base_user.py
b/airflow-core/src/airflow/api_fastapi/auth/managers/models/base_user.py
index 7f060f3121e..c94ee0c1d8d 100644
--- a/airflow-core/src/airflow/api_fastapi/auth/managers/models/base_user.py
+++ b/airflow-core/src/airflow/api_fastapi/auth/managers/models/base_user.py
@@ -28,3 +28,12 @@ class BaseUser:
@abstractmethod
def get_name(self) -> str: ...
+
+ def get_display_name(self) -> str:
+ """
+ Return a human-friendly display name for the user.
+
+ Not abstract for backward compatibility reasons: auth managers written
+ before this method existed keep working without any change.
+ """
+ return self.get_name()
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
index d5807bfec27..fea2773828c 100644
---
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
+++
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
@@ -4644,6 +4644,20 @@ paths:
description: "Case-insensitive substring match (SQL `ILIKE`). Slower
than\
\ `owner_prefix_pattern` on large tables \u2014 see \"Filtering with
pattern\
\ parameters\"."
+ - name: owner_display_name_pattern
+ in: query
+ required: false
+ schema:
+ anyOf:
+ - type: string
+ - type: 'null'
+ description: "Case-insensitive substring match (SQL `ILIKE`). Slower
than\
+ \ `owner_display_name_prefix_pattern` on large tables \u2014 see
\"Filtering\
+ \ with pattern parameters\"."
+ title: Owner Display Name Pattern
+ description: "Case-insensitive substring match (SQL `ILIKE`). Slower
than\
+ \ `owner_display_name_prefix_pattern` on large tables \u2014 see
\"Filtering\
+ \ with pattern parameters\"."
- name: event_pattern
in: query
required: false
@@ -4706,6 +4720,18 @@ paths:
title: Owner Prefix Pattern
description: Case-sensitive, index-friendly prefix match. See
"Filtering with
pattern parameters".
+ - name: owner_display_name_prefix_pattern
+ in: query
+ required: false
+ schema:
+ anyOf:
+ - type: string
+ - type: 'null'
+ description: Case-sensitive, index-friendly prefix match. See
"Filtering
+ with pattern parameters".
+ title: Owner Display Name Prefix Pattern
+ description: Case-sensitive, index-friendly prefix match. See
"Filtering with
+ pattern parameters".
- name: event_prefix_pattern
in: query
required: false
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/event_logs.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/event_logs.py
index 881f9f5db1a..eb0c4009814 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/event_logs.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/event_logs.py
@@ -141,6 +141,10 @@ def get_event_logs(
task_id_pattern: Annotated[_SearchParam,
Depends(search_param_factory(Log.task_id, "task_id_pattern"))],
run_id_pattern: Annotated[_SearchParam,
Depends(search_param_factory(Log.run_id, "run_id_pattern"))],
owner_pattern: Annotated[_SearchParam,
Depends(search_param_factory(Log.owner, "owner_pattern"))],
+ owner_display_name_pattern: Annotated[
+ _SearchParam,
+ Depends(search_param_factory(Log.owner_display_name,
"owner_display_name_pattern")),
+ ],
event_pattern: Annotated[_SearchParam,
Depends(search_param_factory(Log.event, "event_pattern"))],
# Prefix pattern search filters (index-friendly, case-sensitive)
dag_id_prefix_pattern: Annotated[
@@ -159,6 +163,10 @@ def get_event_logs(
_PrefixSearchParam,
Depends(prefix_search_param_factory(Log.owner,
"owner_prefix_pattern")),
],
+ owner_display_name_prefix_pattern: Annotated[
+ _PrefixSearchParam,
+ Depends(prefix_search_param_factory(Log.owner_display_name,
"owner_display_name_prefix_pattern")),
+ ],
event_prefix_pattern: Annotated[
_PrefixSearchParam,
Depends(prefix_search_param_factory(Log.event,
"event_prefix_pattern")),
@@ -202,6 +210,8 @@ def get_event_logs(
run_id_prefix_pattern,
owner_pattern,
owner_prefix_pattern,
+ owner_display_name_pattern,
+ owner_display_name_prefix_pattern,
event_pattern,
event_prefix_pattern,
# Permission
diff --git a/airflow-core/src/airflow/api_fastapi/logging/decorators.py
b/airflow-core/src/airflow/api_fastapi/logging/decorators.py
index f32a2bffc70..7c32c70a5ca 100644
--- a/airflow-core/src/airflow/api_fastapi/logging/decorators.py
+++ b/airflow-core/src/airflow/api_fastapi/logging/decorators.py
@@ -98,7 +98,7 @@ def action_logging(event: str | None = None):
user_display = ""
else:
user_name = user.get_name()
- user_display = user.get_name()
+ user_display = user.get_display_name()
has_json_body = "application/json" in
request.headers.get("content-type", "") and await request.body()
request_body = {}
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
index 05a4b47ec1b..2761037fcc2 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
@@ -389,7 +389,7 @@ export const UseEventLogServiceGetEventLogKeyFn = ({
eventLogId }: {
export type EventLogServiceGetEventLogsDefaultResponse =
Awaited<ReturnType<typeof EventLogService.getEventLogs>>;
export type EventLogServiceGetEventLogsQueryResult<TData =
EventLogServiceGetEventLogsDefaultResponse, TError = unknown> =
UseQueryResult<TData, TError>;
export const useEventLogServiceGetEventLogsKey = "EventLogServiceGetEventLogs";
-export const UseEventLogServiceGetEventLogsKeyFn = ({ after, before, dagId,
dagIdPattern, dagIdPrefixPattern, event, eventPattern, eventPrefixPattern,
excludedEvents, includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerPattern, ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern,
taskId, taskIdPattern, taskIdPrefixPattern, tryNumber }: {
+export const UseEventLogServiceGetEventLogsKeyFn = ({ after, before, dagId,
dagIdPattern, dagIdPrefixPattern, event, eventPattern, eventPrefixPattern,
excludedEvents, includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerDisplayNamePattern, ownerDisplayNamePrefixPattern, ownerPattern,
ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern, taskId,
taskIdPattern, taskIdPrefixPattern, tryNumber }: {
after?: string;
before?: string;
dagId?: string;
@@ -405,6 +405,8 @@ export const UseEventLogServiceGetEventLogsKeyFn = ({
after, before, dagId, dagI
offset?: number;
orderBy?: string[];
owner?: string;
+ ownerDisplayNamePattern?: string;
+ ownerDisplayNamePrefixPattern?: string;
ownerPattern?: string;
ownerPrefixPattern?: string;
runId?: string;
@@ -414,7 +416,7 @@ export const UseEventLogServiceGetEventLogsKeyFn = ({
after, before, dagId, dagI
taskIdPattern?: string;
taskIdPrefixPattern?: string;
tryNumber?: number;
-} = {}, queryKey?: Array<unknown>) => [useEventLogServiceGetEventLogsKey,
...(queryKey ?? [{ after, before, dagId, dagIdPattern, dagIdPrefixPattern,
event, eventPattern, eventPrefixPattern, excludedEvents, includedEvents, limit,
mapIndex, offset, orderBy, owner, ownerPattern, ownerPrefixPattern, runId,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
tryNumber }])];
+} = {}, queryKey?: Array<unknown>) => [useEventLogServiceGetEventLogsKey,
...(queryKey ?? [{ after, before, dagId, dagIdPattern, dagIdPrefixPattern,
event, eventPattern, eventPrefixPattern, excludedEvents, includedEvents, limit,
mapIndex, offset, orderBy, owner, ownerDisplayNamePattern,
ownerDisplayNamePrefixPattern, ownerPattern, ownerPrefixPattern, runId,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
tryNumber }])];
export type ExtraLinksServiceGetExtraLinksDefaultResponse =
Awaited<ReturnType<typeof ExtraLinksService.getExtraLinks>>;
export type ExtraLinksServiceGetExtraLinksQueryResult<TData =
ExtraLinksServiceGetExtraLinksDefaultResponse, TError = unknown> =
UseQueryResult<TData, TError>;
export const useExtraLinksServiceGetExtraLinksKey =
"ExtraLinksServiceGetExtraLinks";
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
index a97bde3062b..f435ab90302 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
@@ -758,16 +758,18 @@ export const ensureUseEventLogServiceGetEventLogData =
(queryClient: QueryClient
* @param data.taskIdPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `task_id_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.runIdPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `run_id_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.ownerPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `owner_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
+* @param data.ownerDisplayNamePattern Case-insensitive substring match (SQL
`ILIKE`). Slower than `owner_display_name_prefix_pattern` on large tables — see
"Filtering with pattern parameters".
* @param data.eventPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `event_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.dagIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.taskIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.runIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.ownerPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
+* @param data.ownerDisplayNamePrefixPattern Case-sensitive, index-friendly
prefix match. See "Filtering with pattern parameters".
* @param data.eventPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @returns EventLogCollectionResponse Successful Response
* @throws ApiError
*/
-export const ensureUseEventLogServiceGetEventLogsData = (queryClient:
QueryClient, { after, before, dagId, dagIdPattern, dagIdPrefixPattern, event,
eventPattern, eventPrefixPattern, excludedEvents, includedEvents, limit,
mapIndex, offset, orderBy, owner, ownerPattern, ownerPrefixPattern, runId,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
tryNumber }: {
+export const ensureUseEventLogServiceGetEventLogsData = (queryClient:
QueryClient, { after, before, dagId, dagIdPattern, dagIdPrefixPattern, event,
eventPattern, eventPrefixPattern, excludedEvents, includedEvents, limit,
mapIndex, offset, orderBy, owner, ownerDisplayNamePattern,
ownerDisplayNamePrefixPattern, ownerPattern, ownerPrefixPattern, runId,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
tryNumber }: {
after?: string;
before?: string;
dagId?: string;
@@ -783,6 +785,8 @@ export const ensureUseEventLogServiceGetEventLogsData =
(queryClient: QueryClien
offset?: number;
orderBy?: string[];
owner?: string;
+ ownerDisplayNamePattern?: string;
+ ownerDisplayNamePrefixPattern?: string;
ownerPattern?: string;
ownerPrefixPattern?: string;
runId?: string;
@@ -792,7 +796,7 @@ export const ensureUseEventLogServiceGetEventLogsData =
(queryClient: QueryClien
taskIdPattern?: string;
taskIdPrefixPattern?: string;
tryNumber?: number;
-} = {}) => queryClient.ensureQueryData({ queryKey:
Common.UseEventLogServiceGetEventLogsKeyFn({ after, before, dagId,
dagIdPattern, dagIdPrefixPattern, event, eventPattern, eventPrefixPattern,
excludedEvents, includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerPattern, ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern,
taskId, taskIdPattern, taskIdPrefixPattern, tryNumber }), queryFn: () =>
EventLogService.getEventLogs({ after, before, dagId, dagIdPattern, dagIdPrefix
[...]
+} = {}) => queryClient.ensureQueryData({ queryKey:
Common.UseEventLogServiceGetEventLogsKeyFn({ after, before, dagId,
dagIdPattern, dagIdPrefixPattern, event, eventPattern, eventPrefixPattern,
excludedEvents, includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerDisplayNamePattern, ownerDisplayNamePrefixPattern, ownerPattern,
ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern, taskId,
taskIdPattern, taskIdPrefixPattern, tryNumber }), queryFn: () =>
EventLogService.getEve [...]
/**
* Get Extra Links
* Get extra links for task instance.
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
index 05732b1907f..a9e1144261a 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
@@ -758,16 +758,18 @@ export const prefetchUseEventLogServiceGetEventLog =
(queryClient: QueryClient,
* @param data.taskIdPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `task_id_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.runIdPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `run_id_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.ownerPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `owner_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
+* @param data.ownerDisplayNamePattern Case-insensitive substring match (SQL
`ILIKE`). Slower than `owner_display_name_prefix_pattern` on large tables — see
"Filtering with pattern parameters".
* @param data.eventPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `event_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.dagIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.taskIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.runIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.ownerPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
+* @param data.ownerDisplayNamePrefixPattern Case-sensitive, index-friendly
prefix match. See "Filtering with pattern parameters".
* @param data.eventPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @returns EventLogCollectionResponse Successful Response
* @throws ApiError
*/
-export const prefetchUseEventLogServiceGetEventLogs = (queryClient:
QueryClient, { after, before, dagId, dagIdPattern, dagIdPrefixPattern, event,
eventPattern, eventPrefixPattern, excludedEvents, includedEvents, limit,
mapIndex, offset, orderBy, owner, ownerPattern, ownerPrefixPattern, runId,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
tryNumber }: {
+export const prefetchUseEventLogServiceGetEventLogs = (queryClient:
QueryClient, { after, before, dagId, dagIdPattern, dagIdPrefixPattern, event,
eventPattern, eventPrefixPattern, excludedEvents, includedEvents, limit,
mapIndex, offset, orderBy, owner, ownerDisplayNamePattern,
ownerDisplayNamePrefixPattern, ownerPattern, ownerPrefixPattern, runId,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
tryNumber }: {
after?: string;
before?: string;
dagId?: string;
@@ -783,6 +785,8 @@ export const prefetchUseEventLogServiceGetEventLogs =
(queryClient: QueryClient,
offset?: number;
orderBy?: string[];
owner?: string;
+ ownerDisplayNamePattern?: string;
+ ownerDisplayNamePrefixPattern?: string;
ownerPattern?: string;
ownerPrefixPattern?: string;
runId?: string;
@@ -792,7 +796,7 @@ export const prefetchUseEventLogServiceGetEventLogs =
(queryClient: QueryClient,
taskIdPattern?: string;
taskIdPrefixPattern?: string;
tryNumber?: number;
-} = {}) => queryClient.prefetchQuery({ queryKey:
Common.UseEventLogServiceGetEventLogsKeyFn({ after, before, dagId,
dagIdPattern, dagIdPrefixPattern, event, eventPattern, eventPrefixPattern,
excludedEvents, includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerPattern, ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern,
taskId, taskIdPattern, taskIdPrefixPattern, tryNumber }), queryFn: () =>
EventLogService.getEventLogs({ after, before, dagId, dagIdPattern,
dagIdPrefixPa [...]
+} = {}) => queryClient.prefetchQuery({ queryKey:
Common.UseEventLogServiceGetEventLogsKeyFn({ after, before, dagId,
dagIdPattern, dagIdPrefixPattern, event, eventPattern, eventPrefixPattern,
excludedEvents, includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerDisplayNamePattern, ownerDisplayNamePrefixPattern, ownerPattern,
ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern, taskId,
taskIdPattern, taskIdPrefixPattern, tryNumber }), queryFn: () =>
EventLogService.getEvent [...]
/**
* Get Extra Links
* Get extra links for task instance.
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
index 8e643f182d4..57a9970cdb7 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
@@ -758,16 +758,18 @@ export const useEventLogServiceGetEventLog = <TData =
Common.EventLogServiceGetE
* @param data.taskIdPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `task_id_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.runIdPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `run_id_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.ownerPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `owner_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
+* @param data.ownerDisplayNamePattern Case-insensitive substring match (SQL
`ILIKE`). Slower than `owner_display_name_prefix_pattern` on large tables — see
"Filtering with pattern parameters".
* @param data.eventPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `event_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.dagIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.taskIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.runIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.ownerPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
+* @param data.ownerDisplayNamePrefixPattern Case-sensitive, index-friendly
prefix match. See "Filtering with pattern parameters".
* @param data.eventPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @returns EventLogCollectionResponse Successful Response
* @throws ApiError
*/
-export const useEventLogServiceGetEventLogs = <TData =
Common.EventLogServiceGetEventLogsDefaultResponse, TError = unknown, TQueryKey
extends Array<unknown> = unknown[]>({ after, before, dagId, dagIdPattern,
dagIdPrefixPattern, event, eventPattern, eventPrefixPattern, excludedEvents,
includedEvents, limit, mapIndex, offset, orderBy, owner, ownerPattern,
ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern, taskId,
taskIdPattern, taskIdPrefixPattern, tryNumber }: {
+export const useEventLogServiceGetEventLogs = <TData =
Common.EventLogServiceGetEventLogsDefaultResponse, TError = unknown, TQueryKey
extends Array<unknown> = unknown[]>({ after, before, dagId, dagIdPattern,
dagIdPrefixPattern, event, eventPattern, eventPrefixPattern, excludedEvents,
includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerDisplayNamePattern, ownerDisplayNamePrefixPattern, ownerPattern,
ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern, taskId,
taskIdPatte [...]
after?: string;
before?: string;
dagId?: string;
@@ -783,6 +785,8 @@ export const useEventLogServiceGetEventLogs = <TData =
Common.EventLogServiceGet
offset?: number;
orderBy?: string[];
owner?: string;
+ ownerDisplayNamePattern?: string;
+ ownerDisplayNamePrefixPattern?: string;
ownerPattern?: string;
ownerPrefixPattern?: string;
runId?: string;
@@ -792,7 +796,7 @@ export const useEventLogServiceGetEventLogs = <TData =
Common.EventLogServiceGet
taskIdPattern?: string;
taskIdPrefixPattern?: string;
tryNumber?: number;
-} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>,
"queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey:
Common.UseEventLogServiceGetEventLogsKeyFn({ after, before, dagId,
dagIdPattern, dagIdPrefixPattern, event, eventPattern, eventPrefixPattern,
excludedEvents, includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerPattern, ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern,
taskId, taskIdPattern, taskIdPrefixPattern, tryNumber }, quer [...]
+} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>,
"queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey:
Common.UseEventLogServiceGetEventLogsKeyFn({ after, before, dagId,
dagIdPattern, dagIdPrefixPattern, event, eventPattern, eventPrefixPattern,
excludedEvents, includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerDisplayNamePattern, ownerDisplayNamePrefixPattern, ownerPattern,
ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern, taskI [...]
/**
* Get Extra Links
* Get extra links for task instance.
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
index 209b45e0200..acd2583f742 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
@@ -758,16 +758,18 @@ export const useEventLogServiceGetEventLogSuspense =
<TData = Common.EventLogSer
* @param data.taskIdPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `task_id_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.runIdPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `run_id_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.ownerPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `owner_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
+* @param data.ownerDisplayNamePattern Case-insensitive substring match (SQL
`ILIKE`). Slower than `owner_display_name_prefix_pattern` on large tables — see
"Filtering with pattern parameters".
* @param data.eventPattern Case-insensitive substring match (SQL `ILIKE`).
Slower than `event_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
* @param data.dagIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.taskIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.runIdPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @param data.ownerPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
+* @param data.ownerDisplayNamePrefixPattern Case-sensitive, index-friendly
prefix match. See "Filtering with pattern parameters".
* @param data.eventPrefixPattern Case-sensitive, index-friendly prefix match.
See "Filtering with pattern parameters".
* @returns EventLogCollectionResponse Successful Response
* @throws ApiError
*/
-export const useEventLogServiceGetEventLogsSuspense = <TData =
Common.EventLogServiceGetEventLogsDefaultResponse, TError = unknown, TQueryKey
extends Array<unknown> = unknown[]>({ after, before, dagId, dagIdPattern,
dagIdPrefixPattern, event, eventPattern, eventPrefixPattern, excludedEvents,
includedEvents, limit, mapIndex, offset, orderBy, owner, ownerPattern,
ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern, taskId,
taskIdPattern, taskIdPrefixPattern, tryNumber }: {
+export const useEventLogServiceGetEventLogsSuspense = <TData =
Common.EventLogServiceGetEventLogsDefaultResponse, TError = unknown, TQueryKey
extends Array<unknown> = unknown[]>({ after, before, dagId, dagIdPattern,
dagIdPrefixPattern, event, eventPattern, eventPrefixPattern, excludedEvents,
includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerDisplayNamePattern, ownerDisplayNamePrefixPattern, ownerPattern,
ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern, taskId, tas [...]
after?: string;
before?: string;
dagId?: string;
@@ -783,6 +785,8 @@ export const useEventLogServiceGetEventLogsSuspense =
<TData = Common.EventLogSe
offset?: number;
orderBy?: string[];
owner?: string;
+ ownerDisplayNamePattern?: string;
+ ownerDisplayNamePrefixPattern?: string;
ownerPattern?: string;
ownerPrefixPattern?: string;
runId?: string;
@@ -792,7 +796,7 @@ export const useEventLogServiceGetEventLogsSuspense =
<TData = Common.EventLogSe
taskIdPattern?: string;
taskIdPrefixPattern?: string;
tryNumber?: number;
-} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>,
"queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey:
Common.UseEventLogServiceGetEventLogsKeyFn({ after, before, dagId,
dagIdPattern, dagIdPrefixPattern, event, eventPattern, eventPrefixPattern,
excludedEvents, includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerPattern, ownerPrefixPattern, runId, runIdPattern, runIdPrefixPattern,
taskId, taskIdPattern, taskIdPrefixPattern, tryNumber [...]
+} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>,
"queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey:
Common.UseEventLogServiceGetEventLogsKeyFn({ after, before, dagId,
dagIdPattern, dagIdPrefixPattern, event, eventPattern, eventPrefixPattern,
excludedEvents, includedEvents, limit, mapIndex, offset, orderBy, owner,
ownerDisplayNamePattern, ownerDisplayNamePrefixPattern, ownerPattern,
ownerPrefixPattern, runId, runIdPattern, runIdPrefixPatter [...]
/**
* Get Extra Links
* Get extra links for task instance.
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
b/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
index 4466ec9d7da..94215ebd52e 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
@@ -2078,11 +2078,13 @@ export class EventLogService {
* @param data.taskIdPattern Case-insensitive substring match (SQL
`ILIKE`). Slower than `task_id_prefix_pattern` on large tables — see "Filtering
with pattern parameters".
* @param data.runIdPattern Case-insensitive substring match (SQL
`ILIKE`). Slower than `run_id_prefix_pattern` on large tables — see "Filtering
with pattern parameters".
* @param data.ownerPattern Case-insensitive substring match (SQL
`ILIKE`). Slower than `owner_prefix_pattern` on large tables — see "Filtering
with pattern parameters".
+ * @param data.ownerDisplayNamePattern Case-insensitive substring match
(SQL `ILIKE`). Slower than `owner_display_name_prefix_pattern` on large tables
— see "Filtering with pattern parameters".
* @param data.eventPattern Case-insensitive substring match (SQL
`ILIKE`). Slower than `event_prefix_pattern` on large tables — see "Filtering
with pattern parameters".
* @param data.dagIdPrefixPattern Case-sensitive, index-friendly prefix
match. See "Filtering with pattern parameters".
* @param data.taskIdPrefixPattern Case-sensitive, index-friendly prefix
match. See "Filtering with pattern parameters".
* @param data.runIdPrefixPattern Case-sensitive, index-friendly prefix
match. See "Filtering with pattern parameters".
* @param data.ownerPrefixPattern Case-sensitive, index-friendly prefix
match. See "Filtering with pattern parameters".
+ * @param data.ownerDisplayNamePrefixPattern Case-sensitive,
index-friendly prefix match. See "Filtering with pattern parameters".
* @param data.eventPrefixPattern Case-sensitive, index-friendly prefix
match. See "Filtering with pattern parameters".
* @returns EventLogCollectionResponse Successful Response
* @throws ApiError
@@ -2110,11 +2112,13 @@ export class EventLogService {
task_id_pattern: data.taskIdPattern,
run_id_pattern: data.runIdPattern,
owner_pattern: data.ownerPattern,
+ owner_display_name_pattern: data.ownerDisplayNamePattern,
event_pattern: data.eventPattern,
dag_id_prefix_pattern: data.dagIdPrefixPattern,
task_id_prefix_pattern: data.taskIdPrefixPattern,
run_id_prefix_pattern: data.runIdPrefixPattern,
owner_prefix_pattern: data.ownerPrefixPattern,
+ owner_display_name_prefix_pattern:
data.ownerDisplayNamePrefixPattern,
event_prefix_pattern: data.eventPrefixPattern
},
errors: {
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
index 37a29af6add..8455306b581 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
@@ -3603,6 +3603,14 @@ export type GetEventLogsData = {
*/
orderBy?: Array<(string)>;
owner?: string | null;
+ /**
+ * Case-insensitive substring match (SQL `ILIKE`). Slower than
`owner_display_name_prefix_pattern` on large tables — see "Filtering with
pattern parameters".
+ */
+ ownerDisplayNamePattern?: string | null;
+ /**
+ * Case-sensitive, index-friendly prefix match. See "Filtering with
pattern parameters".
+ */
+ ownerDisplayNamePrefixPattern?: string | null;
/**
* Case-insensitive substring match (SQL `ILIKE`). Slower than
`owner_prefix_pattern` on large tables — see "Filtering with pattern
parameters".
*/
diff --git a/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
b/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
index 9737a4a48ca..e193ac00dd6 100644
--- a/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
@@ -66,7 +66,7 @@ const eventsColumn = (
},
{
accessorKey: "owner",
- cell: ({ row: { original } }) => original.owner_display_name ??
original.owner,
+ cell: ({ row: { original } }) => original.owner_display_name,
enableSorting: true,
header: translate("auditLog.columns.user"),
meta: {
@@ -204,8 +204,8 @@ export const Events = () => {
value: eventTypeFilter,
});
const ownerArg = useAdvancedSearchArg({
- patternApiKey: "ownerPattern",
- prefixApiKey: "ownerPrefixPattern",
+ patternApiKey: "ownerDisplayNamePattern",
+ prefixApiKey: "ownerDisplayNamePrefixPattern",
storageKey: USER_PARAM,
value: userFilter,
});
diff --git
a/airflow-core/src/airflow/api_fastapi/auth/managers/models/base_user.py
b/airflow-core/tests/unit/api_fastapi/auth/managers/models/__init__.py
similarity index 77%
copy from airflow-core/src/airflow/api_fastapi/auth/managers/models/base_user.py
copy to airflow-core/tests/unit/api_fastapi/auth/managers/models/__init__.py
index 7f060f3121e..13a83393a91 100644
--- a/airflow-core/src/airflow/api_fastapi/auth/managers/models/base_user.py
+++ b/airflow-core/tests/unit/api_fastapi/auth/managers/models/__init__.py
@@ -1,4 +1,3 @@
-#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -15,16 +14,3 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-from __future__ import annotations
-
-from abc import abstractmethod
-
-
-class BaseUser:
- """User model interface."""
-
- @abstractmethod
- def get_id(self) -> str: ...
-
- @abstractmethod
- def get_name(self) -> str: ...
diff --git
a/airflow-core/src/airflow/api_fastapi/auth/managers/models/base_user.py
b/airflow-core/tests/unit/api_fastapi/auth/managers/models/test_base_user.py
similarity index 65%
copy from airflow-core/src/airflow/api_fastapi/auth/managers/models/base_user.py
copy to
airflow-core/tests/unit/api_fastapi/auth/managers/models/test_base_user.py
index 7f060f3121e..51ad5028dc9 100644
--- a/airflow-core/src/airflow/api_fastapi/auth/managers/models/base_user.py
+++ b/airflow-core/tests/unit/api_fastapi/auth/managers/models/test_base_user.py
@@ -1,4 +1,3 @@
-#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -17,14 +16,18 @@
# under the License.
from __future__ import annotations
-from abc import abstractmethod
+from airflow.api_fastapi.auth.managers.models.base_user import BaseUser
+
+
+class UserWithoutDisplayName(BaseUser):
+ """An auth manager user predating get_display_name (only get_id / get_name
defined)."""
+ def get_id(self) -> str:
+ return "user-id"
-class BaseUser:
- """User model interface."""
+ def get_name(self) -> str:
+ return "user-name"
- @abstractmethod
- def get_id(self) -> str: ...
- @abstractmethod
- def get_name(self) -> str: ...
+def test_get_display_name_defaults_to_get_name():
+ assert UserWithoutDisplayName().get_display_name() == "user-name"
diff --git
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_event_logs.py
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_event_logs.py
index 564c383a1ff..871692f98d2 100644
---
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_event_logs.py
+++
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_event_logs.py
@@ -403,6 +403,20 @@ class TestGetEventLogs(TestEventLogsEndpoint):
assert event_log["owner"] == OWNER_AIRFLOW
assert event_log["owner_display_name"] == OWNER_AIRFLOW
+ def test_get_event_logs_filters_by_owner_display_name_pattern(self,
test_client):
+ response = test_client.get("/eventLogs",
params={"owner_display_name_pattern": "est Own"})
+
+ assert response.status_code == 200
+ events = {event_log["event"] for event_log in
response.json()["event_logs"]}
+ assert events == {EVENT_WITH_OWNER, EVENT_WITH_OWNER_AND_TASK_INSTANCE}
+
+ def test_get_event_logs_filters_by_owner_display_name_prefix_pattern(self,
test_client):
+ response = test_client.get("/eventLogs",
params={"owner_display_name_prefix_pattern": "Test"})
+
+ assert response.status_code == 200
+ events = {event_log["event"] for event_log in
response.json()["event_logs"]}
+ assert events == {EVENT_WITH_OWNER, EVENT_WITH_OWNER_AND_TASK_INSTANCE}
+
# Ordering of nulls values is DB specific.
@pytest.mark.backend("sqlite")
@pytest.mark.parametrize(
diff --git a/airflow-core/tests/unit/api_fastapi/logging/test_decorators.py
b/airflow-core/tests/unit/api_fastapi/logging/test_decorators.py
index 41b9883d6d3..2adffbe4544 100644
--- a/airflow-core/tests/unit/api_fastapi/logging/test_decorators.py
+++ b/airflow-core/tests/unit/api_fastapi/logging/test_decorators.py
@@ -16,14 +16,20 @@
# under the License.
from __future__ import annotations
+import asyncio
import json
+from unittest.mock import MagicMock
import pytest
+from fastapi import Request
+from sqlalchemy.orm import Session
+from airflow.api_fastapi.auth.managers.models.base_user import BaseUser
from airflow.api_fastapi.logging.decorators import (
_mask_connection_fields,
_mask_variable_fields,
_sanitize_for_stdlib_log,
+ action_logging,
)
@@ -122,3 +128,28 @@ class TestMaskVariableFields:
def test_value_without_key_is_still_masked(self):
result = _mask_variable_fields({"value": "secretval"})
assert result == {"value": "***"}
+
+
+class TestActionLoggingUserFields:
+ """The audit Log records the raw identifier in ``owner`` and the
human-friendly
+ ``get_display_name()`` in ``owner_display_name``."""
+
+ def test_owner_and_display_name_use_the_matching_user_methods(self):
+ class FakeUser(BaseUser):
+ def get_id(self) -> str:
+ return "id"
+
+ def get_name(self) -> str:
+ return "jdoe"
+
+ def get_display_name(self) -> str:
+ return "Jane Doe"
+
+ request = Request({"type": "http", "method": "GET", "headers": [],
"query_string": b""})
+ session = MagicMock(spec=Session)
+
+ asyncio.run(action_logging(event="test_event")(request=request,
session=session, user=FakeUser()))
+
+ (logged,) = session.add.call_args.args
+ assert logged.owner == "jdoe"
+ assert logged.owner_display_name == "Jane Doe"
diff --git
a/providers/fab/src/airflow/providers/fab/auth_manager/models/__init__.py
b/providers/fab/src/airflow/providers/fab/auth_manager/models/__init__.py
index 598f13b2219..ecdac36f421 100644
--- a/providers/fab/src/airflow/providers/fab/auth_manager/models/__init__.py
+++ b/providers/fab/src/airflow/providers/fab/auth_manager/models/__init__.py
@@ -363,6 +363,9 @@ class User(Model, BaseUser):
def get_full_name(self):
return f"{self.first_name} {self.last_name}"
+ def get_display_name(self) -> str:
+ return self.get_full_name()
+
def __repr__(self):
return self.get_full_name()
diff --git
a/providers/fab/tests/unit/fab/auth_manager/models/test_user_model.py
b/providers/fab/tests/unit/fab/auth_manager/models/test_user_model.py
index f780871676e..c054463c303 100644
--- a/providers/fab/tests/unit/fab/auth_manager/models/test_user_model.py
+++ b/providers/fab/tests/unit/fab/auth_manager/models/test_user_model.py
@@ -36,3 +36,10 @@ def test_get_id_returns_str(user_id: int, expected_id: str)
-> None:
result = user.get_id()
assert isinstance(result, str), f"Expected str, got {type(result)}"
assert result == expected_id
+
+
+def test_get_display_name_uses_full_name() -> None:
+ user = User()
+ user.first_name = "Jane"
+ user.last_name = "Doe"
+ assert user.get_display_name() == "Jane Doe"