feat: audit logs on organization-level support

This commit is contained in:
Daniel Hougaard
2024-09-08 19:24:04 +04:00
parent bda9bb3d61
commit 7b19d2aa6a
3 changed files with 86 additions and 14 deletions

View File

@@ -1,6 +1,7 @@
import { z } from "zod";
import {
AuditLogsSchema,
GroupsSchema,
IncidentContactsSchema,
OrganizationsSchema,
@@ -8,7 +9,9 @@ import {
OrgRolesSchema,
UsersSchema
} from "@app/db/schemas";
import { ORGANIZATIONS } from "@app/lib/api-docs";
import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
import { AUDIT_LOGS, ORGANIZATIONS } from "@app/lib/api-docs";
import { getLastMidnightDateISO } from "@app/lib/fn";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -62,6 +65,69 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
}
});
server.route({
method: "GET",
url: "/audit-logs",
config: {
rateLimit: readLimit
},
schema: {
description: "Get all audit logs for an organization",
querystring: z.object({
eventType: z.nativeEnum(EventType).optional().describe(AUDIT_LOGS.EXPORT.eventType),
userAgentType: z.nativeEnum(UserAgentType).optional().describe(AUDIT_LOGS.EXPORT.userAgentType),
startDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.startDate),
endDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.endDate),
offset: z.coerce.number().default(0).describe(AUDIT_LOGS.EXPORT.offset),
limit: z.coerce.number().default(20).describe(AUDIT_LOGS.EXPORT.limit),
actor: z.string().optional().describe(AUDIT_LOGS.EXPORT.actor)
}),
response: {
200: z.object({
auditLogs: AuditLogsSchema.omit({
eventMetadata: true,
eventType: true,
actor: true,
actorMetadata: true
})
.merge(
z.object({
project: z.object({
name: z.string(),
slug: z.string()
}),
event: z.object({
type: z.string(),
metadata: z.any()
}),
actor: z.object({
type: z.string(),
metadata: z.any()
})
})
)
.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const auditLogs = await server.services.auditLog.listAuditLogs({
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
...req.query,
endDate: req.query.endDate,
startDate: req.query.startDate || getLastMidnightDateISO(),
auditLogActor: req.query.actor,
actor: req.permission.type,
projectId: null
});
return { auditLogs };
}
});
server.route({
method: "GET",
url: "/:organizationId/users",

View File

@@ -5,27 +5,29 @@ import { apiRequest } from "@app/config/request";
import { Actor, AuditLog, AuditLogFilters } from "./types";
export const workspaceKeys = {
getAuditLogs: (workspaceId: string, filters: AuditLogFilters) =>
getAuditLogs: (filters: AuditLogFilters, workspaceId: string | null) =>
[{ workspaceId, filters }, "audit-logs"] as const,
getAuditLogActorFilterOpts: (workspaceId: string) =>
[{ workspaceId }, "audit-log-actor-filters"] as const
};
export const useGetAuditLogs = (workspaceId: string, filters: AuditLogFilters) => {
export const useGetAuditLogs = (filters: AuditLogFilters, workspaceId: string | null) => {
return useInfiniteQuery({
queryKey: workspaceKeys.getAuditLogs(workspaceId, filters),
queryKey: workspaceKeys.getAuditLogs(filters, workspaceId),
enabled: workspaceId !== "",
queryFn: async ({ pageParam }) => {
const { data } = await apiRequest.get<{ auditLogs: AuditLog[] }>(
`/api/v1/workspace/${workspaceId}/audit-logs`,
{
params: {
...filters,
offset: pageParam,
startDate: filters?.startDate?.toISOString(),
endDate: filters?.endDate?.toISOString()
}
const auditLogEndpoint = workspaceId
? `/api/v1/workspace/${workspaceId}/audit-logs`
: "/api/v1/organization/audit-logs";
const { data } = await apiRequest.get<{ auditLogs: AuditLog[] }>(auditLogEndpoint, {
params: {
...filters,
offset: pageParam,
startDate: filters?.startDate?.toISOString(),
endDate: filters?.endDate?.toISOString()
}
);
});
return data.auditLogs;
},
getNextPageParam: (lastPage, pages) =>

View File

@@ -830,6 +830,10 @@ export type AuditLog = {
userAgentType: UserAgentType;
createdAt: string;
updatedAt: string;
project: {
name: string;
slug: string;
};
};
export type AuditLogFilters = {