mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-07-24 07:42:47 +00:00
feat: complete remaining features — training, FTS, bot groups, repair, re-tag
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Manual override training (GroupingRule): - Learn patterns from manual group creation (common filename prefix or creator) - Apply learned rules as first auto-grouping pass (highest confidence after albums) - GroupingRule model stores pattern, channel, signal type, confidence Hash verification after upload: - Re-hash upload files on disk before indexing to catch disk corruption - Creates HASH_MISMATCH notification on discrepancy Grouping conflict detection: - After all grouping passes, check if grouped packages match rules from different groups - Creates GROUPING_CONFLICT notification for manual review Per-channel grouping flags: - Add autoGroupEnabled boolean to TelegramChannel (default true) - Auto-grouping passes (all except album) gated behind this flag - Album grouping always runs as it reflects Telegram's native behavior Full-text search (tsvector): - Add searchVector tsvector column with GIN index and auto-update trigger - Backfill 1870 existing packages - FTS with ts_rank for ranked results, ILIKE fallback for short/failed queries - Applied to both web app and bot search Bot group awareness: - /group <query> — view group info or search groups by name - /sendgroup <id> — send all packages in a group to linked Telegram account Bulk repair: - repairPackageAction clears dest info and resets watermark for re-processing - Repair button in notification bell for MISSING_PART and HASH_MISMATCH alerts - /api/notifications/repair endpoint Retroactive category re-tagging: - When channel category changes, auto-update tags on all existing packages - Removes old category tag, adds new one Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -53,7 +53,52 @@ export async function createTelegramLink(
|
||||
// ── Package search ──
|
||||
|
||||
export async function searchPackages(query: string, limit = 10) {
|
||||
const packages = await db.package.findMany({
|
||||
// Try full-text search first
|
||||
if (query.length >= 3) {
|
||||
const tsQuery = query
|
||||
.trim()
|
||||
.split(/\s+/)
|
||||
.filter((w) => w.length >= 2)
|
||||
.map((w) => w.replace(/[^a-zA-Z0-9]/g, ""))
|
||||
.filter(Boolean)
|
||||
.join(" & ");
|
||||
|
||||
if (tsQuery) {
|
||||
try {
|
||||
const ftsResults = await db.$queryRawUnsafe<{ id: string }[]>(
|
||||
`SELECT id FROM packages
|
||||
WHERE "searchVector" @@ to_tsquery('english', $1)
|
||||
ORDER BY ts_rank("searchVector", to_tsquery('english', $1)) DESC
|
||||
LIMIT $2`,
|
||||
tsQuery,
|
||||
limit
|
||||
);
|
||||
|
||||
if (ftsResults.length > 0) {
|
||||
return db.package.findMany({
|
||||
where: { id: { in: ftsResults.map((r) => r.id) } },
|
||||
orderBy: { indexedAt: "desc" },
|
||||
select: {
|
||||
id: true,
|
||||
fileName: true,
|
||||
fileSize: true,
|
||||
archiveType: true,
|
||||
fileCount: true,
|
||||
creator: true,
|
||||
indexedAt: true,
|
||||
destChannelId: true,
|
||||
destMessageId: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// FTS failed — fall back to ILIKE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: ILIKE search
|
||||
return db.package.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{ fileName: { contains: query, mode: "insensitive" } },
|
||||
@@ -74,7 +119,44 @@ export async function searchPackages(query: string, limit = 10) {
|
||||
destMessageId: true,
|
||||
},
|
||||
});
|
||||
return packages;
|
||||
}
|
||||
|
||||
// ── Group queries ──
|
||||
|
||||
export async function getGroupById(groupId: string) {
|
||||
return db.packageGroup.findUnique({
|
||||
where: { id: groupId },
|
||||
include: {
|
||||
packages: {
|
||||
orderBy: { indexedAt: "desc" },
|
||||
select: {
|
||||
id: true,
|
||||
fileName: true,
|
||||
fileSize: true,
|
||||
archiveType: true,
|
||||
fileCount: true,
|
||||
creator: true,
|
||||
destChannelId: true,
|
||||
destMessageId: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function searchGroups(query: string, limit = 5) {
|
||||
return db.packageGroup.findMany({
|
||||
where: {
|
||||
name: { contains: query, mode: "insensitive" },
|
||||
},
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: limit,
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
_count: { select: { packages: true } },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function getLatestPackages(limit = 5) {
|
||||
|
||||
Reference in New Issue
Block a user