Skip to content

Commit b74dd32

Browse files
perf: Optimize DB calls and avoid N+1 queries in BookingAuditViewer (calcom#26544)
* Integrate creation/rescheduling booking audit * fix: add missing hostUserUuid to booking audit test data Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix-ci * feat: enhance booking audit with seat reference - Added support for seat reference in booking audit actions. - Updated localization for booking creation to include seat information. - Modified relevant services to pass attendee seat ID during booking creation. * fix: update test data to match schema requirements - Add seatReferenceUid: null to default mock audit log data - Add seatReferenceUid: null to multiple audit logs test case - Convert SEAT_RESCHEDULED test data to use numeric timestamps instead of ISO strings Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * Allow nullish seatReferenceUid * feat: enhance booking audit to support rescheduledBy information - Updated booking audit actions to include rescheduledBy details, allowing tracking of who rescheduled a booking. - Refactored related services to accommodate the new rescheduledBy parameter in booking events. - Adjusted type definitions and function signatures to reflect the changes in the booking audit context. * Avoid possible run time issue * Fix imoport path * fix failing test due to merge from main\ * Pass useruuid * Refactor getDisplayTitle method signatures to use _params for consistency across audit action services. Update IAuditActionService to include dbStore in GetDisplayTitleParams for improved data handling during title retrieval. * fix: extend bulk-fetching optimization to actor and impersonator enrichment - Collect actor userUuids (for USER type actors) in collectDataRequirements - Collect impersonator UUIDs from log.context.impersonatedBy - Update enrichActorInformation to use dbStore.getUserByUuid() for USER actors - Update enrichImpersonator to use dbStore.getUserByUuid() - Update tests to verify findByUuids is called with correct aggregated UUIDs Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * feat: Add infrastructure for no-show audit integration - Add Prisma migrations for SYSTEM source and NO_SHOW_UPDATED audit action - Add NoShowUpdatedAuditActionService with array-based attendeesNoShow schema - Update BookingAuditActionServiceRegistry to include NO_SHOW_UPDATED - Update BookingAuditTaskConsumer and BookingAuditViewerService - Add AttendeeRepository methods for no-show queries - Update IAuditActionService interface with values array support - Update locales with no-show audit translation keys Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Add NO_SHOW_UPDATED to BookingAuditAction and SYSTEM to ActionSource types Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Remove HOST_NO_SHOW_UPDATED and ATTENDEE_NO_SHOW_UPDATED from BookingAuditAction type to match Prisma schema Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Update BookingAuditActionSchema to use NO_SHOW_UPDATED instead of HOST_NO_SHOW_UPDATED and ATTENDEE_NO_SHOW_UPDATED Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * refactor: Remove deprecated no-show audit services and unify to NoShowUpdatedAuditActionService - Delete HostNoShowUpdatedAuditActionService and AttendeeNoShowUpdatedAuditActionService - Update BookingAuditProducerService.interface.ts to use queueNoShowUpdatedAudit - Update BookingAuditTaskerProducerService.ts to use queueNoShowUpdatedAudit - Update BookingEventHandlerService.ts to use onNoShowUpdated - Add integration tests for NoShowUpdatedAuditActionService Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Add data migration step for deprecated no-show enum values Addresses Cubic AI review feedback (confidence 9/10): The migration now includes an UPDATE statement to convert existing records using the deprecated 'host_no_show_updated' or 'attendee_no_show_updated' enum values to the new unified 'no_show_updated' value before the type cast. This prevents migration failures if any existing data uses the old values. Co-Authored-By: unknown <> * fix: Use CASE expression in USING clause for enum migration Fixes PostgreSQL error 'unsafe use of new value of enum type' by avoiding the ADD VALUE statement and instead using a CASE expression in the ALTER TABLE USING clause to convert deprecated enum values (host_no_show_updated, attendee_no_show_updated) to the new unified value (no_show_updated) during the type conversion. Co-Authored-By: unknown <> * fix: Remove dbStore usage from audit action services after merge - Update CreatedAuditActionService to use userRepository.findByUuid directly - Remove unused dbStore parameter from RescheduledAuditActionService - Sync test file with prepare-for-no-show-audit branch Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Restore dbStore bulk-fetching optimization pattern - Add dbStore parameter and getDataRequirements method to IAuditActionService interface - Update CreatedAuditActionService to use dbStore.getUserByUuid() for bulk-fetched data - Update RescheduledAuditActionService to accept dbStore parameter - Update BookingAuditViewerService to: - Collect data requirements from all audit logs - Bulk-fetch users with findByUuids() before enrichment - Pass dbStore to action services and enrichment methods - Update tests to verify findByUuids is called for bulk-fetching optimization Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Remove duplicate fireBookingEvents method in RecurringBookingService Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * revert: Remove formatting-only changes in audit action services Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * feat: Make getDataRequirements required and fetch rescheduled logs early - Make getDataRequirements a required method in IAuditActionService interface - Add getDataRequirements to all action services that didn't have it - Fetch rescheduled logs early to include their data requirements in bulk fetch - Update ReassignmentAuditActionService to use dbStore pattern instead of repository - Update NoShowUpdatedAuditActionService to use dbStore pattern - Update tests to use new dbStore pattern - Handle invalid data gracefully in collectDataRequirements Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * Remve unncessary variable * feat: Implement Actor Strategy pattern for bulk-fetching attendees and credentials - Add ActorStrategies.ts with strategy pattern for all 5 actor types - Extend EnrichmentDataStore with StoredAttendee and StoredCredential types - Add findByIds method to CredentialRepository for bulk-fetching - Update BookingAuditViewerService to use strategy pattern: - Replace switch statement in enrichActorInformation with strategy dispatch - Update collectDataRequirements to collect attendeeIds and credentialIds - Update buildEnrichmentDataStore to bulk-fetch in parallel - Update tests to use findByIds mock and reflect graceful handling of missing data Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Restore error-throwing for actors with missing required IDs - USER actor now throws error when userUuid is missing - ATTENDEE actor now throws error when attendeeId is missing - Updated tests to expect hasError: true for fallback logs Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Restore original test assertions, only update mocks for bulk methods Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * test: Add contract verification tests for getDataRequirements Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * refactor: Clean up imports and improve type definitions in BookingAuditTaskConsumer and BookingAuditViewerService - Consolidated import statements for better readability - Enhanced type definitions for clarity and consistency - Updated method signatures to use destructured parameters for improved maintainability Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * test: Split contract verification tests into separate files per action service Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * test: Rename contract test files to .test.ts and merge into existing test file Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * feat: Add runtime validation to EnrichmentDataStore for undeclared data access Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * refactor: Make declaredRequirements required and add ensureFetched helper Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * refactor: Simplify EnrichmentDataStore with constructor + fetch() pattern - Remove unused userIds and bookingUids from DataRequirements - Remove unused getUserById and getBookingByUid methods - Refactor constructor to accept requirements and repositories - Add fetch() method that fetches data and populates maps - Use Map keys as source of truth for declared requirements - Update getters to throw when accessing undeclared data - Add comprehensive unit tests for EnrichmentDataStore - Update BookingAuditViewerService to use new API - Update contractVerification.ts to remove unused tracking Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * refactor: Clean up imports and improve type definitions in BookingAuditTaskConsumer and BookingAuditViewerService - Consolidated import statements for better readability - Enhanced type definitions for clarity and consistency - Updated method signatures to use destructured parameters for improved maintainability Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fix: Include contextRequirements in mergeDataRequirements and add accessedData assertions - Fix bug where contextRequirements (impersonator UUIDs) were not merged - Add accessedData assertions to CreatedAuditActionService.test.ts - Add accessedData assertions to ReassignmentAuditActionService.test.ts Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 39135f8 commit b74dd32

37 files changed

Lines changed: 2183 additions & 761 deletions

packages/features/booking-audit/lib/actions/AcceptedAuditActionService.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { BookingStatus } from "@calcom/prisma/enums";
22
import { z } from "zod";
33

44
import { BookingStatusChangeSchema } from "../common/changeSchemas";
5+
import type { DataRequirements } from "../service/EnrichmentDataStore";
56
import { AuditActionServiceHelper } from "./AuditActionServiceHelper";
67
import type { IAuditActionService, TranslationWithParams, GetDisplayTitleParams, GetDisplayJsonParams } from "./IAuditActionService";
78

@@ -59,6 +60,10 @@ export class AcceptedAuditActionService implements IAuditActionService {
5960
return { isMigrated: false, latestData: validated };
6061
}
6162

63+
getDataRequirements(): DataRequirements {
64+
return { userUuids: [] };
65+
}
66+
6267
async getDisplayTitle(_: GetDisplayTitleParams): Promise<TranslationWithParams> {
6368
return { key: "booking_audit_action.accepted" };
6469
}

packages/features/booking-audit/lib/actions/AttendeeAddedAuditActionService.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { z } from "zod";
22
import { emailSchema } from "@calcom/lib/emailSchema";
33

4+
import type { DataRequirements } from "../service/EnrichmentDataStore";
45
import { AuditActionServiceHelper } from "./AuditActionServiceHelper";
56
import type {
67
IAuditActionService,
@@ -63,6 +64,10 @@ export class AttendeeAddedAuditActionService implements IAuditActionService {
6364
return { isMigrated: false, latestData: validated };
6465
}
6566

67+
getDataRequirements(): DataRequirements {
68+
return { userUuids: [] };
69+
}
70+
6671
async getDisplayTitle(_: GetDisplayTitleParams): Promise<TranslationWithParams> {
6772
return { key: "booking_audit_action.attendee_added" };
6873
}

packages/features/booking-audit/lib/actions/AttendeeRemovedAuditActionService.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { z } from "zod";
22

33
import { StringArrayChangeSchema } from "../common/changeSchemas";
4+
import type { DataRequirements } from "../service/EnrichmentDataStore";
45
import { AuditActionServiceHelper } from "./AuditActionServiceHelper";
56
import type { IAuditActionService, TranslationWithParams, GetDisplayTitleParams, GetDisplayJsonParams } from "./IAuditActionService";
67

@@ -58,6 +59,10 @@ export class AttendeeRemovedAuditActionService implements IAuditActionService {
5859
return { isMigrated: false, latestData: validated };
5960
}
6061

62+
getDataRequirements(): DataRequirements {
63+
return { userUuids: [] };
64+
}
65+
6166
async getDisplayTitle(_: GetDisplayTitleParams): Promise<TranslationWithParams> {
6267
return { key: "booking_audit_action.attendee_removed" };
6368
}

packages/features/booking-audit/lib/actions/CancelledAuditActionService.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { z } from "zod";
22

3-
import { StringChangeSchema, BookingStatusChangeSchema } from "../common/changeSchemas";
3+
import { BookingStatusChangeSchema } from "../common/changeSchemas";
4+
import type { DataRequirements } from "../service/EnrichmentDataStore";
45
import { AuditActionServiceHelper } from "./AuditActionServiceHelper";
56
import type { IAuditActionService, TranslationWithParams, GetDisplayTitleParams, GetDisplayJsonParams } from "./IAuditActionService";
67

@@ -60,6 +61,10 @@ export class CancelledAuditActionService implements IAuditActionService {
6061
return { isMigrated: false, latestData: validated };
6162
}
6263

64+
getDataRequirements(): DataRequirements {
65+
return { userUuids: [] };
66+
}
67+
6368
async getDisplayTitle(_: GetDisplayTitleParams): Promise<TranslationWithParams> {
6469
return { key: "booking_audit_action.cancelled" };
6570
}

packages/features/booking-audit/lib/actions/CreatedAuditActionService.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { z } from "zod";
22
import { BookingStatus } from "@calcom/prisma/enums";
3-
import type { UserRepository } from "@calcom/features/users/repositories/UserRepository";
43

54
import { AuditActionServiceHelper } from "./AuditActionServiceHelper";
6-
import type { IAuditActionService, TranslationWithParams, GetDisplayTitleParams, GetDisplayJsonParams } from "./IAuditActionService";
5+
import type { IAuditActionService, TranslationWithParams, GetDisplayTitleParams, GetDisplayJsonParams, BaseStoredAuditData } from "./IAuditActionService";
6+
import type { DataRequirements } from "../service/EnrichmentDataStore";
77

88
/**
99
* Created Audit Action Service
@@ -21,9 +21,6 @@ const fieldsSchemaV1 = z.object({
2121
seatReferenceUid: z.string().nullish(),
2222
});
2323

24-
type Deps = {
25-
userRepository: UserRepository;
26-
};
2724
export class CreatedAuditActionService implements IAuditActionService {
2825
readonly VERSION = 1;
2926
public static readonly TYPE = "CREATED" as const;
@@ -39,7 +36,7 @@ export class CreatedAuditActionService implements IAuditActionService {
3936
public static readonly storedFieldsSchema = CreatedAuditActionService.fieldsSchemaV1;
4037
private helper: AuditActionServiceHelper<typeof CreatedAuditActionService.latestFieldsSchema, typeof CreatedAuditActionService.storedDataSchema>;
4138

42-
constructor(private readonly deps: Deps) {
39+
constructor() {
4340
this.helper = new AuditActionServiceHelper({
4441
latestVersion: this.VERSION,
4542
latestFieldsSchema: CreatedAuditActionService.latestFieldsSchema,
@@ -65,9 +62,16 @@ export class CreatedAuditActionService implements IAuditActionService {
6562
return { isMigrated: false, latestData: validated };
6663
}
6764

68-
async getDisplayTitle({ storedData }: GetDisplayTitleParams): Promise<TranslationWithParams> {
65+
getDataRequirements(storedData: BaseStoredAuditData): DataRequirements {
66+
const { fields } = this.parseStored(storedData);
67+
return {
68+
userUuids: fields.hostUserUuid ? [fields.hostUserUuid] : [],
69+
};
70+
}
71+
72+
async getDisplayTitle({ storedData, dbStore }: GetDisplayTitleParams): Promise<TranslationWithParams> {
6973
const { fields } = this.parseStored(storedData);
70-
const hostUser = fields.hostUserUuid ? await this.deps.userRepository.findByUuid({ uuid: fields.hostUserUuid }) : null;
74+
const hostUser = fields.hostUserUuid ? dbStore.getUserByUuid(fields.hostUserUuid) : null;
7175
const hostName = hostUser?.name || "Unknown";
7276
if (fields.seatReferenceUid) {
7377
return { key: "booking_audit_action.created_with_seat", params: { host: hostName } };

packages/features/booking-audit/lib/actions/IAuditActionService.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export type TranslationWithParams = {
1818
components?: TranslationComponent[];
1919
};
2020

21+
import type { EnrichmentDataStore, DataRequirements } from "../service/EnrichmentDataStore";
22+
2123
/**
2224
* This is agnostic of the action and is common for all actions
2325
*/
@@ -34,10 +36,12 @@ export type GetDisplayJsonParams = {
3436
export type GetDisplayTitleParams = {
3537
storedData: BaseStoredAuditData;
3638
userTimeZone: string;
39+
dbStore: EnrichmentDataStore;
3740
};
3841

3942
export type GetDisplayFieldsParams = {
4043
storedData: BaseStoredAuditData;
44+
dbStore: EnrichmentDataStore;
4145
};
4246

4347
/**
@@ -88,6 +92,14 @@ export interface IAuditActionService {
8892
*/
8993
getDisplayJson?(params: GetDisplayJsonParams): Record<string, unknown>;
9094

95+
/**
96+
* Declare what data this action needs from DB
97+
* Returns identifiers to be bulk-fetched before enrichment
98+
* @param storedData - Parsed stored data { version, fields }
99+
* @returns Data requirements with arrays of identifiers to fetch
100+
*/
101+
getDataRequirements(storedData: BaseStoredAuditData): DataRequirements;
102+
91103
/**
92104
* Get the display title for the audit action
93105
* Returns a translation key with optional interpolation params for dynamic titles

packages/features/booking-audit/lib/actions/LocationChangedAuditActionService.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { z } from "zod";
22

33
import { getHumanReadableLocationValue } from "@calcom/app-store/locations";
44
import { StringChangeSchema } from "../common/changeSchemas";
5+
import type { DataRequirements } from "../service/EnrichmentDataStore";
56
import { AuditActionServiceHelper } from "./AuditActionServiceHelper";
67
import type {
78
IAuditActionService,
@@ -63,6 +64,10 @@ export class LocationChangedAuditActionService implements IAuditActionService {
6364
return { isMigrated: false, latestData: validated };
6465
}
6566

67+
getDataRequirements(): DataRequirements {
68+
return { userUuids: [] };
69+
}
70+
6671
async getDisplayTitle({ storedData }: GetDisplayTitleParams): Promise<TranslationWithParams> {
6772
const { fields } = this.parseStored(storedData);
6873
// TODO: Ideally we want to translate the location label to the user's locale

packages/features/booking-audit/lib/actions/NoShowUpdatedAuditActionService.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import type { IAttendeeRepository } from "@calcom/features/bookings/repositories/IAttendeeRepository";
2-
import type { UserRepository } from "@calcom/features/users/repositories/UserRepository";
31
import type { Ensure } from "@calcom/types/utils";
42
import { z } from "zod";
53
import { BooleanChangeSchema } from "../common/changeSchemas";
4+
import type { DataRequirements } from "../service/EnrichmentDataStore";
65
import { AuditActionServiceHelper } from "./AuditActionServiceHelper";
76
import type {
7+
BaseStoredAuditData,
88
GetDisplayFieldsParams,
99
GetDisplayJsonParams,
1010
GetDisplayTitleParams,
@@ -31,11 +31,6 @@ const fieldsSchemaV1 = z
3131
message: "At least one of host or attendeesNoShow must be provided",
3232
});
3333

34-
type Deps = {
35-
attendeeRepository: IAttendeeRepository;
36-
userRepository: UserRepository;
37-
};
38-
3934
export class NoShowUpdatedAuditActionService implements IAuditActionService {
4035
readonly VERSION = 1;
4136
public static readonly TYPE = "NO_SHOW_UPDATED" as const;
@@ -54,7 +49,7 @@ export class NoShowUpdatedAuditActionService implements IAuditActionService {
5449
typeof NoShowUpdatedAuditActionService.storedDataSchema
5550
>;
5651

57-
constructor(private readonly deps: Deps) {
52+
constructor() {
5853
this.helper = new AuditActionServiceHelper({
5954
latestVersion: this.VERSION,
6055
latestFieldsSchema: NoShowUpdatedAuditActionService.latestFieldsSchema,
@@ -90,9 +85,17 @@ export class NoShowUpdatedAuditActionService implements IAuditActionService {
9085
return fields.attendeesNoShow !== undefined;
9186
}
9287

88+
getDataRequirements(storedData: BaseStoredAuditData): DataRequirements {
89+
const { fields: parsedFields } = this.parseStored(storedData);
90+
const userUuids: string[] = [];
91+
if (this.isHostSet(parsedFields)) {
92+
userUuids.push(parsedFields.host.userUuid);
93+
}
94+
return { userUuids };
95+
}
96+
9397
async getDisplayTitle({ storedData }: GetDisplayTitleParams): Promise<TranslationWithParams> {
94-
const { fields } = this.parseStored({ version: storedData.version, fields: storedData.fields });
95-
const parsedFields = fields as NoShowUpdatedAuditData;
98+
const { fields: parsedFields } = this.parseStored({ version: storedData.version, fields: storedData.fields });
9699
if (this.isHostSet(parsedFields) && this.isAttendeesNoShowSet(parsedFields)) {
97100
return { key: "booking_audit_action.no_show_updated" };
98101
}
@@ -105,16 +108,15 @@ export class NoShowUpdatedAuditActionService implements IAuditActionService {
105108
throw new Error("Audit action data is invalid");
106109
}
107110

108-
async getDisplayFields({ storedData }: GetDisplayFieldsParams): Promise<
111+
async getDisplayFields({ storedData, dbStore }: GetDisplayFieldsParams): Promise<
109112
Array<{
110113
labelKey: string;
111114
valueKey?: string;
112115
value?: string;
113116
values?: string[];
114117
}>
115118
> {
116-
const { fields } = this.parseStored(storedData);
117-
const parsedFields = fields as NoShowUpdatedAuditData;
119+
const { fields: parsedFields } = this.parseStored(storedData);
118120
const displayFields: { labelKey: string; valueKey?: string; value?: string; values?: string[] }[] = [];
119121

120122
if (this.isAttendeesNoShowSet(parsedFields)) {
@@ -126,7 +128,7 @@ export class NoShowUpdatedAuditActionService implements IAuditActionService {
126128
}
127129

128130
if (this.isHostSet(parsedFields)) {
129-
const user = await this.deps.userRepository.findByUuid({ uuid: parsedFields.host.userUuid });
131+
const user = dbStore.getUserByUuid(parsedFields.host.userUuid);
130132
const hostName = user?.name || "Unknown";
131133
const hostFieldValue = `${hostName}:${parsedFields.host.noShow.new ? "Yes" : "No"}`;
132134
displayFields.push({ labelKey: "Host", value: hostFieldValue });

packages/features/booking-audit/lib/actions/ReassignmentAuditActionService.ts

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import type { UserRepository } from "@calcom/features/users/repositories/UserRepository";
21
import { z } from "zod";
32
import { StringChangeSchema } from "../common/changeSchemas";
3+
import type { DataRequirements, EnrichmentDataStore } from "../service/EnrichmentDataStore";
44
import { AuditActionServiceHelper } from "./AuditActionServiceHelper";
55
import type {
6+
BaseStoredAuditData,
67
GetDisplayFieldsParams,
78
GetDisplayJsonParams,
89
GetDisplayTitleParams,
@@ -46,7 +47,7 @@ export class ReassignmentAuditActionService implements IAuditActionService {
4647
typeof ReassignmentAuditActionService.storedDataSchema
4748
>;
4849

49-
constructor(private userRepository: UserRepository) {
50+
constructor() {
5051
this.helper = new AuditActionServiceHelper({
5152
latestVersion: this.VERSION,
5253
latestFieldsSchema: ReassignmentAuditActionService.latestFieldsSchema,
@@ -72,9 +73,30 @@ export class ReassignmentAuditActionService implements IAuditActionService {
7273
return { isMigrated: false, latestData: validated };
7374
}
7475

75-
async getDisplayTitle({ storedData }: GetDisplayTitleParams): Promise<TranslationWithParams> {
76+
getDataRequirements(storedData: BaseStoredAuditData): DataRequirements {
7677
const { fields } = this.parseStored(storedData);
77-
const { newUser } = await this.getPreviousAndNewAssigneeUser(fields);
78+
const userUuids: string[] = [];
79+
const { newHostUuid, previousHostUuid } = this.getHostUuids(fields);
80+
if (newHostUuid) userUuids.push(newHostUuid);
81+
if (previousHostUuid) userUuids.push(previousHostUuid);
82+
return { userUuids };
83+
}
84+
85+
private getHostUuids(fields: ReassignmentAuditData) {
86+
const hasAttendeeUpdated = fields.hostAttendeeUpdated != null;
87+
const newHostUuid = hasAttendeeUpdated
88+
? fields.hostAttendeeUpdated?.withUserUuid?.new
89+
: fields.organizerUuid?.new;
90+
const previousHostUuid = hasAttendeeUpdated
91+
? fields.hostAttendeeUpdated?.withUserUuid?.old
92+
: fields.organizerUuid?.old;
93+
return { newHostUuid, previousHostUuid };
94+
}
95+
96+
async getDisplayTitle({ storedData, dbStore }: GetDisplayTitleParams): Promise<TranslationWithParams> {
97+
const { fields } = this.parseStored(storedData);
98+
const { newHostUuid } = this.getHostUuids(fields);
99+
const newUser = newHostUuid ? dbStore.getUserByUuid(newHostUuid) : null;
78100
const reassignedToName = newUser?.name || "Unknown";
79101
return {
80102
key: "booking_audit_action.booking_reassigned_to_host",
@@ -103,27 +125,7 @@ export class ReassignmentAuditActionService implements IAuditActionService {
103125
};
104126
}
105127

106-
private async getPreviousAndNewAssigneeUser(fields: ReassignmentAuditData) {
107-
const hasAttendeeUpdated = fields.hostAttendeeUpdated != null;
108-
const newHostUuid = hasAttendeeUpdated
109-
? fields.hostAttendeeUpdated?.withUserUuid?.new
110-
: fields.organizerUuid?.new;
111-
const previousHostUuid = hasAttendeeUpdated
112-
? fields.hostAttendeeUpdated?.withUserUuid?.old
113-
: fields.organizerUuid?.old;
114-
115-
const newUser = newHostUuid ? await this.userRepository.findByUuid({ uuid: newHostUuid }) : null;
116-
const previousUser = previousHostUuid
117-
? await this.userRepository.findByUuid({ uuid: previousHostUuid })
118-
: null;
119-
120-
return {
121-
previousUser: previousUser,
122-
newUser: newUser,
123-
};
124-
}
125-
126-
async getDisplayFields({ storedData }: GetDisplayFieldsParams): Promise<
128+
async getDisplayFields({ storedData, dbStore }: GetDisplayFieldsParams): Promise<
127129
Array<{
128130
labelKey: string;
129131
valueKey: string;
@@ -135,7 +137,8 @@ export class ReassignmentAuditActionService implements IAuditActionService {
135137
roundRobin: "round_robin",
136138
};
137139
const typeTranslationKey = `booking_audit_action.assignment_type_${map[fields.reassignmentType]}`;
138-
const { previousUser } = await this.getPreviousAndNewAssigneeUser(fields);
140+
const { previousHostUuid } = this.getHostUuids(fields);
141+
const previousUser = previousHostUuid ? dbStore.getUserByUuid(previousHostUuid) : null;
139142
return [
140143
{
141144
labelKey: "booking_audit_action.assignment_type",

packages/features/booking-audit/lib/actions/RejectedAuditActionService.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { z } from "zod";
22

33
import { BookingStatusChangeSchema } from "../common/changeSchemas";
4+
import type { DataRequirements } from "../service/EnrichmentDataStore";
45
import { AuditActionServiceHelper } from "./AuditActionServiceHelper";
56
import type {
67
IAuditActionService,
@@ -65,6 +66,10 @@ export class RejectedAuditActionService implements IAuditActionService {
6566
return { isMigrated: false, latestData: validated };
6667
}
6768

69+
getDataRequirements(): DataRequirements {
70+
return { userUuids: [] };
71+
}
72+
6873
async getDisplayTitle(_: GetDisplayTitleParams): Promise<TranslationWithParams> {
6974
return { key: "booking_audit_action.rejected" };
7075
}

0 commit comments

Comments
 (0)