* feat: booking reports and blocklist table * chore: save progress * chore: save progress * feat: finish * fix: types and test * fix: types and test * refactor: separate tables * refactor: ffedbac * refactor: remove delete report * refactor: add go back button * feat: add icon and svg * chore: nit * fix: type errror * fix: type errror * refactor: code improvements * chore: add docs url * chore: feedback * minor UI fix * fix: add Is-calcom check --------- Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: CarinaWolli <wollencarina@gmail.com>
226 lines
5.6 KiB
TypeScript
226 lines
5.6 KiB
TypeScript
import type { PrismaClient } from "@calcom/prisma";
|
|
import type { Prisma } from "@calcom/prisma/generated/prisma/client";
|
|
|
|
import type {
|
|
IBookingReportRepository,
|
|
CreateBookingReportInput,
|
|
BookingReportWithDetails,
|
|
ListBookingReportsFilters,
|
|
} from "./bookingReport.interface";
|
|
|
|
export class PrismaBookingReportRepository implements IBookingReportRepository {
|
|
constructor(private readonly prismaClient: PrismaClient) {}
|
|
|
|
async createReport(input: CreateBookingReportInput): Promise<{ id: string }> {
|
|
const report = await this.prismaClient.bookingReport.create({
|
|
data: {
|
|
bookingUid: input.bookingUid,
|
|
bookerEmail: input.bookerEmail,
|
|
reportedById: input.reportedById,
|
|
reason: input.reason,
|
|
description: input.description,
|
|
cancelled: input.cancelled,
|
|
organizationId: input.organizationId,
|
|
},
|
|
select: { id: true },
|
|
});
|
|
return report;
|
|
}
|
|
|
|
async findAllReportedBookings(params: {
|
|
organizationId?: number;
|
|
skip?: number;
|
|
take?: number;
|
|
searchTerm?: string;
|
|
filters?: ListBookingReportsFilters;
|
|
}): Promise<{
|
|
rows: BookingReportWithDetails[];
|
|
meta: { totalRowCount: number };
|
|
}> {
|
|
const where: Prisma.BookingReportWhereInput = {};
|
|
|
|
if (params.organizationId) {
|
|
where.organizationId = params.organizationId;
|
|
}
|
|
|
|
if (params.searchTerm) {
|
|
where.OR = [
|
|
{ bookerEmail: { contains: params.searchTerm, mode: "insensitive" } },
|
|
{
|
|
reportedBy: {
|
|
email: { contains: params.searchTerm, mode: "insensitive" },
|
|
},
|
|
},
|
|
];
|
|
}
|
|
|
|
if (params.filters?.hasWatchlist !== undefined) {
|
|
where.watchlistId = params.filters.hasWatchlist ? { not: null } : null;
|
|
}
|
|
|
|
if (params.filters?.reason && params.filters.reason.length > 0) {
|
|
where.reason = { in: params.filters.reason };
|
|
}
|
|
|
|
if (params.filters?.cancelled !== undefined) {
|
|
where.cancelled = params.filters.cancelled;
|
|
}
|
|
|
|
if (params.filters?.status && params.filters.status.length > 0) {
|
|
where.status = { in: params.filters.status };
|
|
}
|
|
|
|
const [reports, totalCount] = await Promise.all([
|
|
this.prismaClient.bookingReport.findMany({
|
|
where,
|
|
skip: params.skip,
|
|
take: params.take,
|
|
select: {
|
|
id: true,
|
|
bookingUid: true,
|
|
bookerEmail: true,
|
|
reportedById: true,
|
|
reason: true,
|
|
description: true,
|
|
cancelled: true,
|
|
createdAt: true,
|
|
status: true,
|
|
watchlistId: true,
|
|
reportedBy: {
|
|
select: {
|
|
id: true,
|
|
email: true,
|
|
name: true,
|
|
},
|
|
},
|
|
booking: {
|
|
select: {
|
|
id: true,
|
|
uid: true,
|
|
title: true,
|
|
startTime: true,
|
|
endTime: true,
|
|
},
|
|
},
|
|
watchlist: {
|
|
select: {
|
|
id: true,
|
|
type: true,
|
|
value: true,
|
|
action: true,
|
|
description: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: { createdAt: "desc" },
|
|
}),
|
|
this.prismaClient.bookingReport.count({ where }),
|
|
]);
|
|
|
|
const rows = reports.map((report) => ({
|
|
...report,
|
|
reporter: report.reportedBy,
|
|
}));
|
|
|
|
return {
|
|
rows,
|
|
meta: { totalRowCount: totalCount },
|
|
};
|
|
}
|
|
|
|
async findReportsByIds(params: {
|
|
reportIds: string[];
|
|
organizationId?: number;
|
|
}): Promise<BookingReportWithDetails[]> {
|
|
const where: Prisma.BookingReportWhereInput = {
|
|
id: { in: params.reportIds },
|
|
};
|
|
|
|
if (params.organizationId) {
|
|
where.organizationId = params.organizationId;
|
|
}
|
|
|
|
const reports = await this.prismaClient.bookingReport.findMany({
|
|
where,
|
|
select: {
|
|
id: true,
|
|
bookingUid: true,
|
|
bookerEmail: true,
|
|
reportedById: true,
|
|
reason: true,
|
|
description: true,
|
|
cancelled: true,
|
|
createdAt: true,
|
|
status: true,
|
|
watchlistId: true,
|
|
reportedBy: {
|
|
select: {
|
|
id: true,
|
|
email: true,
|
|
name: true,
|
|
},
|
|
},
|
|
booking: {
|
|
select: {
|
|
id: true,
|
|
uid: true,
|
|
title: true,
|
|
startTime: true,
|
|
endTime: true,
|
|
},
|
|
},
|
|
watchlist: {
|
|
select: {
|
|
id: true,
|
|
type: true,
|
|
value: true,
|
|
action: true,
|
|
description: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
return reports.map((report) => ({
|
|
...report,
|
|
reporter: report.reportedBy,
|
|
}));
|
|
}
|
|
|
|
async linkWatchlistToReport(params: { reportId: string; watchlistId: string }): Promise<void> {
|
|
await this.prismaClient.bookingReport.update({
|
|
where: { id: params.reportId },
|
|
data: { watchlistId: params.watchlistId },
|
|
});
|
|
}
|
|
|
|
async updateReportStatus(params: {
|
|
reportId: string;
|
|
status: "PENDING" | "DISMISSED" | "BLOCKED";
|
|
organizationId?: number;
|
|
}): Promise<void> {
|
|
const where: Prisma.BookingReportWhereInput = {
|
|
id: params.reportId,
|
|
};
|
|
|
|
if (params.organizationId) {
|
|
where.organizationId = params.organizationId;
|
|
}
|
|
|
|
await this.prismaClient.bookingReport.updateMany({
|
|
where,
|
|
data: { status: params.status },
|
|
});
|
|
}
|
|
|
|
async countPendingReports(params: { organizationId: number }): Promise<number> {
|
|
return this.prismaClient.bookingReport.count({
|
|
where: {
|
|
organizationId: params.organizationId,
|
|
status: "PENDING",
|
|
watchlistId: null,
|
|
},
|
|
});
|
|
}
|
|
}
|