diff --git a/src/lib/telegram/queries.ts b/src/lib/telegram/queries.ts index d72cb23..e328f5e 100644 --- a/src/lib/telegram/queries.ts +++ b/src/lib/telegram/queries.ts @@ -4,6 +4,7 @@ import type { PackageDetail, PackageFileItem, IngestionAccountStatus, + SkippedPackageItem, } from "./types"; export async function listPackages(options: { @@ -336,3 +337,52 @@ export async function getIngestionStatus(): Promise { return statuses; } + +export async function listSkippedPackages(options: { + page: number; + limit: number; + reason?: "SIZE_LIMIT" | "DOWNLOAD_FAILED" | "EXTRACT_FAILED" | "UPLOAD_FAILED"; +}) { + const where: Record = {}; + if (options.reason) where.reason = options.reason; + + const [items, total] = await Promise.all([ + prisma.skippedPackage.findMany({ + where, + orderBy: { createdAt: "desc" }, + skip: (options.page - 1) * options.limit, + take: options.limit, + include: { + sourceChannel: { select: { id: true, title: true } }, + }, + }), + prisma.skippedPackage.count({ where }), + ]); + + const mapped: SkippedPackageItem[] = items.map((s) => ({ + id: s.id, + fileName: s.fileName, + fileSize: s.fileSize.toString(), + reason: s.reason, + errorMessage: s.errorMessage, + sourceChannel: s.sourceChannel, + sourceMessageId: s.sourceMessageId.toString(), + isMultipart: s.isMultipart, + partCount: s.partCount, + createdAt: s.createdAt.toISOString(), + })); + + return { + items: mapped, + pagination: { + page: options.page, + limit: options.limit, + total, + totalPages: Math.ceil(total / options.limit), + }, + }; +} + +export async function countSkippedPackages(): Promise { + return prisma.skippedPackage.count(); +} diff --git a/src/lib/telegram/types.ts b/src/lib/telegram/types.ts index 4432d14..03b487c 100644 --- a/src/lib/telegram/types.ts +++ b/src/lib/telegram/types.ts @@ -42,6 +42,22 @@ export interface PackageFileItem { crc32: string | null; } +export interface SkippedPackageItem { + id: string; + fileName: string; + fileSize: string; + reason: "SIZE_LIMIT" | "DOWNLOAD_FAILED" | "EXTRACT_FAILED" | "UPLOAD_FAILED"; + errorMessage: string | null; + sourceChannel: { + id: string; + title: string; + }; + sourceMessageId: string; + isMultipart: boolean; + partCount: number; + createdAt: string; +} + export interface PaginatedResponse { items: T[]; pagination: {