Files
Hariom BalharaGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2802310268 feat: Add infrastructure for no-show audit integration (#27187)
* 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: [email protected] <[email protected]>

* fix: Add NO_SHOW_UPDATED to BookingAuditAction and SYSTEM to ActionSource types

Co-Authored-By: [email protected] <[email protected]>

* fix: Remove HOST_NO_SHOW_UPDATED and ATTENDEE_NO_SHOW_UPDATED from BookingAuditAction type to match Prisma schema

Co-Authored-By: [email protected] <[email protected]>

* fix: Update BookingAuditActionSchema to use NO_SHOW_UPDATED instead of HOST_NO_SHOW_UPDATED and ATTENDEE_NO_SHOW_UPDATED

Co-Authored-By: [email protected] <[email protected]>

* 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: [email protected] <[email protected]>

* 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: Replace hardcoded color with semantic text-success class

Co-Authored-By: [email protected] <[email protected]>

* fix: Remove color class completely from display fields

Co-Authored-By: [email protected] <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-29 08:47:26 -03:00

144 lines
3.4 KiB
TypeScript

import type { PrismaClient } from "@calcom/prisma";
import type { IAttendeeRepository } from "./IAttendeeRepository";
const safeSelect = {
id: true,
email: true,
name: true,
locale: true,
timeZone: true,
phoneNumber: true,
bookingId: true,
noShow: true,
};
/**
* Prisma-based implementation of IAttendeeRepository
*
* This repository provides methods for looking up attendee information.
*/
export class AttendeeRepository implements IAttendeeRepository {
constructor(private prismaClient: PrismaClient) {}
async findById(id: number): Promise<{ name: string; email: string } | null> {
const attendee = await this.prismaClient.attendee.findUnique({
where: { id },
select: {
name: true,
email: true,
},
});
return attendee;
}
async findByIds({ ids }: { ids: number[] }): Promise<{ id: number; name: string; email: string }[]> {
return this.prismaClient.attendee.findMany({
where: { id: { in: ids } },
select: {
id: true,
name: true,
email: true,
},
});
}
async findByBookingIdAndSeatReference({
bookingId,
seatReferenceUid,
}: {
bookingId: number;
seatReferenceUid: string;
}): Promise<{ email: string }[]> {
return this.prismaClient.attendee.findMany({
where: {
bookingId,
bookingSeat: {
referenceUid: seatReferenceUid,
},
},
select: { email: true },
});
}
async findByBookingUidAndEmails({
bookingUid,
emails,
}: {
bookingUid: string;
emails: string[];
}): Promise<{ id: number; email: string; noShow: boolean | null }[]> {
return this.prismaClient.attendee.findMany({
where: {
booking: { uid: bookingUid },
email: { in: emails },
},
select: { id: true, email: true, noShow: true },
});
}
async updateNoShow({
where: { attendeeId },
data: { noShow },
}: {
where: { attendeeId: number };
data: { noShow: boolean };
}): Promise<{ noShow: boolean | null; email: string }> {
return this.prismaClient.attendee.update({
where: { id: attendeeId },
data: { noShow },
select: { noShow: true, email: true },
});
}
async findByBookingId(bookingId: number): Promise<
{
id: number;
email: string;
name: string;
locale: string | null;
timeZone: string;
phoneNumber: string | null;
bookingId: number | null;
noShow: boolean | null;
}[]
> {
return this.prismaClient.attendee.findMany({
where: { bookingId },
select: safeSelect,
});
}
async updateManyNoShowByBookingIdAndEmails({
where: { bookingId, emails },
data: { noShow },
}: {
where: { bookingId: number; emails: string[] };
data: { noShow: boolean };
}): Promise<{ count: number }> {
return this.prismaClient.attendee.updateMany({
where: {
bookingId,
email: { in: emails },
},
data: { noShow },
});
}
async updateManyNoShowByBookingIdExcludingEmails({
where: { bookingId, excludeEmails },
data: { noShow },
}: {
where: { bookingId: number; excludeEmails: string[] };
data: { noShow: boolean };
}): Promise<{ count: number }> {
return this.prismaClient.attendee.updateMany({
where: {
bookingId,
email: { notIn: excludeEmails },
},
data: { noShow },
});
}
}