* feat: extract core booking audit infrastructure from PR 25125 This PR contains only the core booking audit infrastructure changes from PR 25125, excluding integration changes with booking flows. Included: - All packages/features/booking-audit/* (core audit services, actions, repository) - packages/features/di/containers/BookingAuditViewerService.container.ts - packages/features/tasker/tasker.ts (audit task types) - packages/features/bookings/lib/types/actor.ts (actor types for audit) - packages/features/bookings/repositories/BookingRepository.ts (getFromRescheduleUid method) - apps/web/modules/booking/logs/views/booking-logs-view.tsx (UI for viewing audit logs) - apps/web/public/static/locales/en/common.json (translations) Excluded (integration changes): - packages/trpc/server/* (tRPC handlers) - packages/features/ee/round-robin/* (round-robin integration) - packages/features/bookings/lib/handleCancelBooking.ts - packages/features/bookings/lib/handleConfirmation.ts - packages/features/bookings/lib/onBookingEvents/BookingEventHandlerService.ts - packages/features/bookings/lib/service/RegularBookingService.ts - apps/api/v2/* (API v2 integration) Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: make booking audit interfaces backwards-compatible with main - Add queueAudit method back to BookingAuditProducerService interface for backwards compatibility - Implement queueAudit method in BookingAuditTaskerProducerService - Make userTimeZone parameter optional in BookingAuditViewerService - Add BookingAuditTaskProducerActionData type for legacy queueAudit method - Use any generics in BookingAuditActionServiceRegistry (matching PR 25125) - Fix type assertions in BookingAuditTaskConsumer Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix switch eslint and ts * feat: enhance BookingAuditViewerService with logging and type improvements - Added ISimpleLogger dependency to BookingAuditViewerService for better error handling. - Updated actor type in enriched audit logs to use AuditActorType for improved type safety. - Replaced console.error with logger for error reporting when no rescheduled log is found. --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
import { z } from "zod";
|
|
import { formatInTimeZone } from "date-fns-tz";
|
|
|
|
/**
|
|
* Audit Action Service Helper
|
|
*
|
|
* Provides reusable utility methods for audit action services via composition.
|
|
*
|
|
* We use composition instead of inheritance for Action services so that services can evolve to v2, v3 independently without polluting a shared base class
|
|
*/
|
|
export class AuditActionServiceHelper<
|
|
TLatestFieldsSchema extends z.ZodTypeAny,
|
|
TStoredDataSchema extends z.ZodTypeAny
|
|
> {
|
|
private readonly latestFieldsSchema: TLatestFieldsSchema;
|
|
private readonly latestVersion: number;
|
|
private readonly storedDataSchema: TStoredDataSchema;
|
|
|
|
constructor({
|
|
/**
|
|
* The schema to validate against latest version
|
|
*/
|
|
latestFieldsSchema,
|
|
latestVersion,
|
|
/**
|
|
* The schema to validate the stored data that could be of any version
|
|
*/
|
|
storedDataSchema,
|
|
}: {
|
|
latestFieldsSchema: TLatestFieldsSchema;
|
|
latestVersion: number;
|
|
storedDataSchema: TStoredDataSchema;
|
|
}) {
|
|
this.latestFieldsSchema = latestFieldsSchema;
|
|
this.latestVersion = latestVersion;
|
|
this.storedDataSchema = storedDataSchema;
|
|
}
|
|
|
|
/**
|
|
* Parse input fields with the latest fields schema and wrap with version
|
|
*/
|
|
getVersionedData(fields: unknown): { version: number; fields: z.infer<TLatestFieldsSchema> } {
|
|
const parsed = this.latestFieldsSchema.parse(fields);
|
|
return {
|
|
version: this.latestVersion,
|
|
fields: parsed,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Parse stored audit record (includes version wrapper)
|
|
* Accepts any version defined in allVersionsDataSchema (for backward compatibility)
|
|
*/
|
|
parseStored(data: unknown): z.infer<TStoredDataSchema> {
|
|
return this.storedDataSchema.parse(data);
|
|
}
|
|
|
|
/**
|
|
* Extract version from stored data
|
|
*/
|
|
getVersion(data: unknown): number {
|
|
const parsed = z.object({ version: z.number() }).parse(data);
|
|
return parsed.version;
|
|
}
|
|
|
|
/**
|
|
* Format date in user's timezone with format: MMM d, yyyy (e.g., "Jul 7, 2025")
|
|
* @param date - Date string or timestamp
|
|
* @param timeZone - User's timezone (defaults to UTC)
|
|
* @returns Formatted date string
|
|
*/
|
|
static formatDateInTimeZone(date: string | number, timeZone: string = "UTC"): string {
|
|
return formatInTimeZone(new Date(date), timeZone, "MMM d, yyyy");
|
|
}
|
|
|
|
/**
|
|
* Format datetime in user's timezone with format: yyyy-MM-dd HH:mm:ss (e.g., "2025-07-07 09:42:10")
|
|
* @param date - Date string or timestamp
|
|
* @param timeZone - User's timezone (defaults to UTC)
|
|
* @returns Formatted datetime string
|
|
*/
|
|
static formatDateTimeInTimeZone(date: string | number, timeZone: string = "UTC"): string {
|
|
return formatInTimeZone(new Date(date), timeZone, "yyyy-MM-dd HH:mm:ss");
|
|
}
|
|
}
|
|
|