mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-05-10 22:01:16 +00:00
Channel Discovery: - Remove channel/supergroup filter from getAccountChats — all chat types (private, groups, Saved Messages, etc.) are now discoverable as sources - Detect and label the self-chat as "Saved Messages" via getMe - Update channel picker dialog to accept any chat type string Bot Rich Messages: - Enhance package send preview with creator, file count, tags, and source channel info in MarkdownV2 caption - Include tags in new_package subscription notifications - Expand getPendingSendRequest to fetch richer package data Performance: - Reviewed pipeline for many-channel load — getChats pagination fix and per-channel getChat pre-load from prior commit address the main concerns - Channels with no new messages skip in 2-3 API calls Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
196 lines
5.0 KiB
TypeScript
196 lines
5.0 KiB
TypeScript
import { db } from "./client.js";
|
|
|
|
// ── Link management ──
|
|
|
|
export async function findLinkByTelegramUserId(telegramUserId: bigint) {
|
|
return db.telegramLink.findUnique({
|
|
where: { telegramUserId },
|
|
});
|
|
}
|
|
|
|
export async function findLinkByUserId(userId: string) {
|
|
return db.telegramLink.findUnique({
|
|
where: { userId },
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Validate a link code stored in global_settings as `link_code:<code>`.
|
|
* Returns the userId if the code is valid, null otherwise.
|
|
*/
|
|
export async function validateLinkCode(code: string): Promise<string | null> {
|
|
const key = `link_code:${code}`;
|
|
const setting = await db.globalSetting.findUnique({ where: { key } });
|
|
if (!setting) return null;
|
|
|
|
try {
|
|
const parsed = JSON.parse(setting.value);
|
|
if (parsed.expiresAt && new Date(parsed.expiresAt) < new Date()) return null;
|
|
return parsed.userId ?? null;
|
|
} catch {
|
|
// Legacy format: value is the userId directly
|
|
return setting.value;
|
|
}
|
|
}
|
|
|
|
export async function deleteLinkCode(code: string): Promise<void> {
|
|
const key = `link_code:${code}`;
|
|
await db.globalSetting.delete({ where: { key } }).catch(() => {});
|
|
}
|
|
|
|
export async function createTelegramLink(
|
|
userId: string,
|
|
telegramUserId: bigint,
|
|
telegramName: string | null
|
|
) {
|
|
return db.telegramLink.upsert({
|
|
where: { userId },
|
|
create: { userId, telegramUserId, telegramName },
|
|
update: { telegramUserId, telegramName },
|
|
});
|
|
}
|
|
|
|
// ── Package search ──
|
|
|
|
export async function searchPackages(query: string, limit = 10) {
|
|
const packages = await db.package.findMany({
|
|
where: {
|
|
OR: [
|
|
{ fileName: { contains: query, mode: "insensitive" } },
|
|
{ creator: { contains: query, mode: "insensitive" } },
|
|
],
|
|
},
|
|
orderBy: { indexedAt: "desc" },
|
|
take: limit,
|
|
select: {
|
|
id: true,
|
|
fileName: true,
|
|
fileSize: true,
|
|
archiveType: true,
|
|
fileCount: true,
|
|
creator: true,
|
|
indexedAt: true,
|
|
destChannelId: true,
|
|
destMessageId: true,
|
|
},
|
|
});
|
|
return packages;
|
|
}
|
|
|
|
export async function getLatestPackages(limit = 5) {
|
|
return db.package.findMany({
|
|
orderBy: { indexedAt: "desc" },
|
|
take: limit,
|
|
select: {
|
|
id: true,
|
|
fileName: true,
|
|
fileSize: true,
|
|
archiveType: true,
|
|
fileCount: true,
|
|
creator: true,
|
|
indexedAt: true,
|
|
destChannelId: true,
|
|
destMessageId: true,
|
|
},
|
|
});
|
|
}
|
|
|
|
export async function getPackageById(id: string) {
|
|
return db.package.findUnique({
|
|
where: { id },
|
|
include: {
|
|
files: { take: 20, orderBy: { path: "asc" } },
|
|
sourceChannel: { select: { title: true } },
|
|
},
|
|
});
|
|
}
|
|
|
|
// ── Send requests ──
|
|
|
|
export async function getPendingSendRequest(requestId: string) {
|
|
return db.botSendRequest.findUnique({
|
|
where: { id: requestId },
|
|
include: {
|
|
package: {
|
|
select: {
|
|
id: true,
|
|
fileName: true,
|
|
fileSize: true,
|
|
fileCount: true,
|
|
creator: true,
|
|
tags: true,
|
|
archiveType: true,
|
|
destChannelId: true,
|
|
destMessageId: true,
|
|
previewData: true,
|
|
sourceChannel: { select: { title: true, telegramId: true } },
|
|
},
|
|
},
|
|
telegramLink: true,
|
|
},
|
|
});
|
|
}
|
|
|
|
export async function updateSendRequest(
|
|
requestId: string,
|
|
status: "SENDING" | "SENT" | "FAILED",
|
|
error?: string
|
|
) {
|
|
return db.botSendRequest.update({
|
|
where: { id: requestId },
|
|
data: {
|
|
status,
|
|
error: error ?? undefined,
|
|
completedAt: status === "SENT" || status === "FAILED" ? new Date() : undefined,
|
|
},
|
|
});
|
|
}
|
|
|
|
// ── Subscriptions ──
|
|
|
|
export async function getSubscriptions(telegramUserId: bigint) {
|
|
return db.botSubscription.findMany({
|
|
where: { telegramUserId },
|
|
orderBy: { createdAt: "desc" },
|
|
});
|
|
}
|
|
|
|
export async function addSubscription(telegramUserId: bigint, pattern: string) {
|
|
return db.botSubscription.upsert({
|
|
where: {
|
|
telegramUserId_pattern: { telegramUserId, pattern },
|
|
},
|
|
create: { telegramUserId, pattern },
|
|
update: {},
|
|
});
|
|
}
|
|
|
|
export async function removeSubscription(telegramUserId: bigint, pattern: string) {
|
|
return db.botSubscription.deleteMany({
|
|
where: { telegramUserId, pattern },
|
|
});
|
|
}
|
|
|
|
export async function findMatchingSubscriptions(fileName: string, creator: string | null) {
|
|
// Get all subscriptions and filter in-memory (simpler for pattern matching)
|
|
const subs = await db.botSubscription.findMany();
|
|
return subs.filter((sub) => {
|
|
const p = sub.pattern.toLowerCase();
|
|
if (fileName.toLowerCase().includes(p)) return true;
|
|
if (creator && creator.toLowerCase().includes(p)) return true;
|
|
return false;
|
|
});
|
|
}
|
|
|
|
// ── Destination channel ──
|
|
|
|
export async function getGlobalDestinationChannel() {
|
|
const setting = await db.globalSetting.findUnique({
|
|
where: { key: "destination_channel_id" },
|
|
});
|
|
if (!setting) return null;
|
|
return db.telegramChannel.findFirst({
|
|
where: { id: setting.value, type: "DESTINATION", isActive: true },
|
|
});
|
|
}
|