mirror of
https://github.com/willchen96/mike.git
synced 2026-06-28 21:49:37 +02:00
Sync CourtListener verification and document safety updates
- Refine CourtListener citation verification, bulk lookup logging, and API fallback behavior - Persist cancelled chat stream output and render cancellation as the final assistant message - Add document/version deletion safety fixes and shared warning/modal UI updates - Sync document panel, case law panel, and response UI styling refinements - Harden OSS sync script to preserve local env, dependency, and generated files
This commit is contained in:
parent
44e868eb42
commit
f32a194b33
24 changed files with 2494 additions and 1222 deletions
|
|
@ -28,6 +28,37 @@ function normalizeDocumentFilename(nextName: unknown, currentName: string) {
|
|||
return `${trimmed}${ext}`;
|
||||
}
|
||||
|
||||
async function deleteProjectDocumentsAndVersionFiles(
|
||||
db: ReturnType<typeof createServerSupabase>,
|
||||
projectId: string,
|
||||
documentIds: string[],
|
||||
) {
|
||||
if (documentIds.length === 0) return null;
|
||||
const { data: versions, error: versionsError } = await db
|
||||
.from("document_versions")
|
||||
.select("storage_path, pdf_storage_path")
|
||||
.in("document_id", documentIds);
|
||||
if (versionsError) return versionsError;
|
||||
|
||||
const paths = new Set<string>();
|
||||
for (const v of versions ?? []) {
|
||||
if (typeof v.storage_path === "string" && v.storage_path.length > 0) {
|
||||
paths.add(v.storage_path);
|
||||
}
|
||||
if (typeof v.pdf_storage_path === "string" && v.pdf_storage_path.length > 0) {
|
||||
paths.add(v.pdf_storage_path);
|
||||
}
|
||||
}
|
||||
await Promise.all([...paths].map((p) => deleteFile(p).catch(() => {})));
|
||||
|
||||
const { error } = await db
|
||||
.from("documents")
|
||||
.delete()
|
||||
.eq("project_id", projectId)
|
||||
.in("id", documentIds);
|
||||
return error ?? null;
|
||||
}
|
||||
|
||||
// GET /projects
|
||||
projectsRouter.get("/", requireAuth, async (req, res) => {
|
||||
const userId = res.locals.userId as string;
|
||||
|
|
@ -710,11 +741,48 @@ projectsRouter.delete("/:projectId/folders/:folderId", requireAuth, async (req,
|
|||
const access = await checkProjectAccess(projectId, userId, userEmail, db);
|
||||
if (!access.ok) return void res.status(404).json({ detail: "Project not found" });
|
||||
|
||||
const folder = await loadProjectFolder(db, projectId, folderId);
|
||||
if (!folder) return void res.status(404).json({ detail: "Folder not found" });
|
||||
const { data: allFolders, error: foldersError } = await db
|
||||
.from("project_subfolders")
|
||||
.select("id, parent_folder_id")
|
||||
.eq("project_id", projectId);
|
||||
if (foldersError)
|
||||
return void res.status(500).json({ detail: foldersError.message });
|
||||
if (!(allFolders ?? []).some((f) => f.id === folderId))
|
||||
return void res.status(404).json({ detail: "Folder not found" });
|
||||
|
||||
// Move direct documents to root before cascade-deleting subfolders
|
||||
await db.from("documents").update({ folder_id: null }).eq("folder_id", folderId).eq("project_id", projectId);
|
||||
const childrenByParent = new Map<string, string[]>();
|
||||
for (const f of allFolders ?? []) {
|
||||
const parentId = f.parent_folder_id as string | null;
|
||||
if (!parentId) continue;
|
||||
const children = childrenByParent.get(parentId) ?? [];
|
||||
children.push(f.id as string);
|
||||
childrenByParent.set(parentId, children);
|
||||
}
|
||||
|
||||
const folderIds = new Set<string>();
|
||||
const stack = [folderId];
|
||||
while (stack.length > 0) {
|
||||
const id = stack.pop()!;
|
||||
if (folderIds.has(id)) continue;
|
||||
folderIds.add(id);
|
||||
stack.push(...(childrenByParent.get(id) ?? []));
|
||||
}
|
||||
|
||||
const { data: docs, error: docsError } = await db
|
||||
.from("documents")
|
||||
.select("id")
|
||||
.eq("project_id", projectId)
|
||||
.in("folder_id", [...folderIds]);
|
||||
if (docsError) return void res.status(500).json({ detail: docsError.message });
|
||||
|
||||
const docIds = (docs ?? []).map((d) => d.id as string);
|
||||
const deleteDocsError = await deleteProjectDocumentsAndVersionFiles(
|
||||
db,
|
||||
projectId,
|
||||
docIds,
|
||||
);
|
||||
if (deleteDocsError)
|
||||
return void res.status(500).json({ detail: deleteDocsError.message });
|
||||
|
||||
const { error } = await db.from("project_subfolders")
|
||||
.delete().eq("id", folderId).eq("project_id", projectId);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue