f1011ddd08
* feat(booking-audit): extract core audit system changes from PR 25125 This PR extracts core audit infrastructure changes without integration changes: 1. New action services introduced: - SeatBookedAuditActionService - SeatRescheduledAuditActionService 2. Simplification of ActionService interface: - Streamlined IAuditActionService interface - Reduced TypeScript burden with cleaner type definitions 3. ActionSource support: - Added BookingAuditSource enum (API_V1, API_V2, WEBAPP, WEBHOOK, UNKNOWN) - Added source and operationId fields to BookingAudit model 4. New AuditAction types: - SEAT_BOOKED - SEAT_RESCHEDULED - APP actor type 5. New BookingAuditAccessService: - Permission-based access control for audit logs - Added readTeamAuditLogs and readOrgAuditLogs permissions 6. Fixes in the logs viewer flow: - Enhanced BookingAuditViewerService with improved filtering - Local AttendeeRepository for actor enrichment Changes are contained within packages/features/booking-audit with minimal outside changes (permission registry only). Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * refactor(booking-audit): streamline action handling and enhance localization - Replaced action icon retrieval with a mapping object for improved clarity and performance. - Introduced constants for actor role labels to simplify role retrieval. - Added new localization strings for audit log permission errors and organization requirements. - Updated various service and repository interfaces to enhance type safety and clarity. - Removed deprecated architecture documentation and adjusted related imports for consistency. These changes aim to improve code maintainability and user experience in the booking audit system. * fix(booking-audit): enhance actor role localization and operation ID tracking - Updated actor role labels in the booking logs view to use lowercase for consistency. - Improved localization by wrapping actor role display in a translation function. - Added operationId field to audit logs for better correlation of actions across multiple bookings. - Enhanced BookingAuditViewerService to include operationId in enriched audit logs. - Updated integration tests to verify consistent operationId across related audit logs. These changes aim to improve localization accuracy and facilitate better tracking of user actions in the booking audit system. * feat: integrate credential repository and enhance app actor handling - Added CredentialRepository to manage app credentials, including a method to find credentials by ID. - Updated BookingAudit system to support app actors identified by credential ID, improving actor attribution and audit clarity. - Introduced a new utility function to map app slugs to display names, enhancing the user experience in audit logs. - Modified relevant interfaces and types to accommodate the new credential handling and app actor structure. - Enhanced BookingAuditViewerService to display app names based on credentials, ensuring accurate representation in audit logs. --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
109 lines
3.9 KiB
TypeScript
109 lines
3.9 KiB
TypeScript
import { z } from "zod";
|
|
|
|
import type { UserRepository } from "@calcom/features/users/repositories/UserRepository";
|
|
import { StringChangeSchema, NumberChangeSchema } from "../common/changeSchemas";
|
|
import { AuditActionServiceHelper } from "./AuditActionServiceHelper";
|
|
import type { IAuditActionService, TranslationWithParams, GetDisplayTitleParams, GetDisplayJsonParams, BaseStoredAuditData } from "./IAuditActionService";
|
|
|
|
/**
|
|
* Reassignment Audit Action Service
|
|
* Handles REASSIGNMENT action with per-action versioning
|
|
*/
|
|
|
|
// Module-level because it is passed to IAuditActionService type outside the class scope
|
|
const fieldsSchemaV1 = z.object({
|
|
assignedToId: NumberChangeSchema,
|
|
assignedById: NumberChangeSchema,
|
|
reassignmentReason: StringChangeSchema,
|
|
reassignmentType: z.enum(["manual", "roundRobin"]),
|
|
userPrimaryEmail: StringChangeSchema.optional(),
|
|
title: StringChangeSchema.optional(),
|
|
});
|
|
|
|
export class ReassignmentAuditActionService implements IAuditActionService {
|
|
readonly VERSION = 1;
|
|
public static readonly TYPE = "REASSIGNMENT" as const;
|
|
private static dataSchemaV1 = z.object({
|
|
version: z.literal(1),
|
|
fields: fieldsSchemaV1,
|
|
});
|
|
private static fieldsSchemaV1 = fieldsSchemaV1;
|
|
public static readonly latestFieldsSchema = fieldsSchemaV1;
|
|
// Union of all versions
|
|
public static readonly storedDataSchema = ReassignmentAuditActionService.dataSchemaV1;
|
|
// Union of all versions
|
|
public static readonly storedFieldsSchema = ReassignmentAuditActionService.fieldsSchemaV1;
|
|
private helper: AuditActionServiceHelper<
|
|
typeof ReassignmentAuditActionService.latestFieldsSchema,
|
|
typeof ReassignmentAuditActionService.storedDataSchema
|
|
>;
|
|
|
|
constructor(private userRepository: UserRepository) {
|
|
this.helper = new AuditActionServiceHelper({
|
|
latestVersion: this.VERSION,
|
|
latestFieldsSchema: ReassignmentAuditActionService.latestFieldsSchema,
|
|
storedDataSchema: ReassignmentAuditActionService.storedDataSchema,
|
|
});
|
|
}
|
|
|
|
getVersionedData(fields: unknown) {
|
|
return this.helper.getVersionedData(fields);
|
|
}
|
|
|
|
parseStored(data: unknown) {
|
|
return this.helper.parseStored(data);
|
|
}
|
|
|
|
getVersion(data: unknown): number {
|
|
return this.helper.getVersion(data);
|
|
}
|
|
|
|
migrateToLatest(data: unknown) {
|
|
// V1-only: validate and return as-is (no migration needed)
|
|
const validated = fieldsSchemaV1.parse(data);
|
|
return { isMigrated: false, latestData: validated };
|
|
}
|
|
|
|
async getDisplayTitle({ storedData }: GetDisplayTitleParams): Promise<TranslationWithParams> {
|
|
const { fields } = this.parseStored(storedData);
|
|
const user = await this.userRepository.findById({ id: fields.assignedToId.new });
|
|
const reassignedToName = user?.name || "Unknown";
|
|
return {
|
|
key: "booking_audit_action.booking_reassigned_to_host",
|
|
params: { host: reassignedToName },
|
|
};
|
|
}
|
|
|
|
getDisplayJson({
|
|
storedData,
|
|
}: GetDisplayJsonParams): ReassignmentAuditDisplayData {
|
|
const { fields } = this.parseStored(storedData);
|
|
return {
|
|
newAssignedToId: fields.assignedToId.new,
|
|
reassignmentReason: fields.reassignmentReason.new ?? null,
|
|
};
|
|
}
|
|
|
|
getDisplayFields(storedData: BaseStoredAuditData): Array<{
|
|
labelKey: string;
|
|
valueKey: string;
|
|
}> {
|
|
const { fields } = storedData;
|
|
const typeTranslationKey = `booking_audit_action.assignmentType_${fields.reassignmentType}`;
|
|
|
|
return [
|
|
{
|
|
labelKey: "booking_audit_action.type",
|
|
valueKey: typeTranslationKey,
|
|
}
|
|
];
|
|
}
|
|
}
|
|
|
|
export type ReassignmentAuditData = z.infer<typeof fieldsSchemaV1>;
|
|
|
|
export type ReassignmentAuditDisplayData = {
|
|
newAssignedToId: number;
|
|
reassignmentReason: string | null;
|
|
};
|