import { Collection, Filter, ObjectId } from "mongodb"; import { getDb } from "../index"; import { applyQueryOptions, QueryOptions, } from "../../talkpilot/utils/query.utils"; import type { Scan, ScanDoc } from "./scans.types"; import { FINISHED_SCAN_STATUSES, SCAN_STATUSES } from "./scans.constants"; import { isInProgressScan } from "./scans.utils"; export const getScansCollection = (): Collection => { return getDb().collection("scans"); }; export const getScansByClientAndDateRange = ( clientId: string, startDate: Date, endDate: Date, ): Promise => { return getScansCollection() .find({ clientId, createdAt: { $gte: startDate, $lte: endDate, }, }) .toArray(); }; export const getScanFieldsByClientAndDateRange = ( clientId: string, startDate: Date, endDate: Date, fields: K[], ): Promise[]> => { const projection = fields.reduce>((acc, field) => { acc[field as string] = 1; return acc; }, {}); return getScansCollection() .find( { clientId, createdAt: { $gte: startDate, $lte: endDate, }, }, { projection }, ) .toArray() as Promise[]>; }; export const createScanDoc = ( scan: Pick & Partial>, ) => { const now = new Date(); return getScansCollection().insertOne({ ...scan, status: SCAN_STATUSES.CHECKING, activeTasksCount: 0, pagesScanned: 0, pagesSkipped: 0, skipped: [], siteChrome: {} as Scan["siteChrome"], createdAt: now, updatedAt: now, startedAt: now, pausedAt: null, completedAt: null, pagesCompleted: 0, pagesFailedPermanent: 0, pagesDuplicate: 0, }); }; export const getScanById = async (id: string): Promise => { return getScansCollection().findOne({ _id: new ObjectId(id) }); }; export const getScansByWebsiteUrl = async ( websiteUrlId: string, ): Promise => { return getScansCollection() .find({ websiteUrlId }) .sort({ createdAt: -1 }) .toArray(); }; export const getLatestScanByWebsiteUrl = async ( websiteUrlId: string, ): Promise => { return getScansCollection().findOne( { websiteUrlId }, { sort: { createdAt: -1 } }, ); }; export const getInProgressScanByWebsiteUrl = async ( websiteUrlId: string, ): Promise => { const latestScan = await getLatestScanByWebsiteUrl(websiteUrlId); if (!latestScan || !isInProgressScan(latestScan)) { return null; } return latestScan; }; export const findInProgressScansByClient = async ( clientId: string, ): Promise => { return getScansCollection() .find({ clientId, status: { $nin: FINISHED_SCAN_STATUSES }, }) .sort({ createdAt: -1 }) .toArray(); }; export const updateScanDoc = async ( scanId: ObjectId, updates: Partial>, ): Promise => { return await getScansCollection().findOneAndUpdate( { _id: scanId }, { $set: { ...updates, updatedAt: new Date() } }, { returnDocument: "after" }, ); }; export const findScansByQuery = async ( query: Filter, options?: QueryOptions, ): Promise => { const cursor = getScansCollection().find(query); return await applyQueryOptions(cursor, options).toArray(); }; export const countScans = async (query: Filter): Promise => { return getScansCollection().countDocuments(query); }; export const hasScansForWebsiteUrl = async ( websiteUrlId: string, ): Promise => { return (await countScans({ websiteUrlId })) > 0; }; export const getLatestCompletedScanByWebsiteUrl = async ( websiteUrlId: string, ): Promise => { return getScansCollection().findOne( { websiteUrlId, status: SCAN_STATUSES.COMPLETED }, { sort: { createdAt: -1 } }, ); }; export const deleteScansByWebsiteUrl = async ( websiteUrlId: string, ): Promise => { const result = await getScansCollection().deleteMany({ websiteUrlId }); return result.deletedCount; }; export const deleteScanById = async (scanId: ObjectId): Promise => { const result = await getScansCollection().deleteOne({ _id: scanId }); return result.deletedCount > 0; };