Revert "fix: import legacy projects without wrapper folder"

This reverts commit 4f8df12fb0.
This commit is contained in:
2026-07-13 15:28:59 +08:00
parent 4f8df12fb0
commit d94cc787b2
2 changed files with 5 additions and 34 deletions
+3 -2
View File
@@ -81,7 +81,7 @@ export async function importLegacyProjects(input: {
sourceRelativePath: entry.sourceRelativePath, sourceRelativePath: entry.sourceRelativePath,
}; };
await writeState(input.stateFile, { version: 1, projects }); await writeState(input.stateFile, { version: 1, projects });
const folderId = await ensureFolderPath(input.prisma, input.organizationId, entry.folderPath); const folderId = await ensureFolderPath(input.prisma, input.organizationId, ["旧教学资产", ...entry.folderPath]);
input.onProgress?.(`import ${entry.legacyId}: ${entry.name}`); input.onProgress?.(`import ${entry.legacyId}: ${entry.name}`);
const created = await createProjectFromOrgAdmin(input.prisma, { const created = await createProjectFromOrgAdmin(input.prisma, {
organizationId: input.organizationId, organizationId: input.organizationId,
@@ -123,7 +123,7 @@ async function ensureFolderPath(
prisma: PrismaClient, prisma: PrismaClient,
organizationId: string, organizationId: string,
parts: readonly string[], parts: readonly string[],
): Promise<string | undefined> { ): Promise<string> {
let parentId: string | undefined; let parentId: string | undefined;
for (const name of parts) { for (const name of parts) {
const existing = await prisma.folder.findFirst({ const existing = await prisma.folder.findFirst({
@@ -141,6 +141,7 @@ async function ensureFolderPath(
}); });
parentId = created.id; parentId = created.id;
} }
if (parentId === undefined) throw new Error("legacy import folder path is empty");
return parentId; return parentId;
} }
@@ -29,7 +29,7 @@ describe("legacy teaching-material project import", () => {
afterAll(async () => prisma.$disconnect()); afterAll(async () => prisma.$disconnect());
it("imports each legacy project as an unbound resumable project under its original folder path", async () => { it("imports each legacy project as an unbound resumable project under its old folder path", async () => {
const sourceRoot = await temporaryRoot("cph-legacy-source-"); const sourceRoot = await temporaryRoot("cph-legacy-source-");
const workspaceRoot = await temporaryRoot("cph-legacy-target-"); const workspaceRoot = await temporaryRoot("cph-legacy-target-");
const projectSource = join(sourceRoot, "物理", "M-243-牛顿力学"); const projectSource = join(sourceRoot, "物理", "M-243-牛顿力学");
@@ -70,7 +70,7 @@ describe("legacy teaching-material project import", () => {
}); });
expect(project.name).toBe("牛顿力学"); expect(project.name).toBe("牛顿力学");
expect(project.folder?.name).toBe("物理"); expect(project.folder?.name).toBe("物理");
expect(project.folder?.parent).toBeNull(); expect(project.folder?.parent?.name).toBe("旧教学资产");
expect(project.groupBindings).toEqual([]); expect(project.groupBindings).toEqual([]);
await expect(readFile(join(imported.workspaceDir, "chapters", "lesson.typ"), "utf8")) await expect(readFile(join(imported.workspaceDir, "chapters", "lesson.typ"), "utf8"))
.resolves.toBe("= 牛顿第二定律\n"); .resolves.toBe("= 牛顿第二定律\n");
@@ -116,36 +116,6 @@ describe("legacy teaching-material project import", () => {
await expect(prisma.project.count({ where: { id: imported.projectId } })).resolves.toBe(1); await expect(prisma.project.count({ where: { id: imported.projectId } })).resolves.toBe(1);
}); });
it("places a legacy project without a source folder in the system Inbox", async () => {
const sourceRoot = await temporaryRoot("cph-legacy-source-");
const workspaceRoot = await temporaryRoot("cph-legacy-target-");
const projectSource = join(sourceRoot, "top-level-project");
await mkdir(join(projectSource, "workspace"), { recursive: true });
await writeFile(join(projectSource, "workspace", "project.toml"), "title = \"顶层项目\"\n");
await writeFile(join(projectSource, "project.json"), "{\"id\":\"top-level\"}\n");
const state = await importLegacyProjects({
prisma,
organizationId: DEFAULT_ORG_ID,
actorFeishuOpenId: "ou_legacy_owner",
workspaceRoot,
sourceRoot,
stateFile: join(workspaceRoot, "state.json"),
projects: [{
legacyId: "top-level",
name: "顶层项目",
folderPath: [],
sourceRelativePath: "top-level-project",
}],
});
const project = await prisma.project.findUniqueOrThrow({
where: { id: state.projects["top-level"]?.projectId },
include: { folder: true },
});
expect(project.folder).toMatchObject({ name: "Inbox", kind: "SYSTEM_INBOX" });
});
it("rejects symlinks instead of importing paths outside the staged project", async () => { it("rejects symlinks instead of importing paths outside the staged project", async () => {
const sourceRoot = await temporaryRoot("cph-legacy-symlink-"); const sourceRoot = await temporaryRoot("cph-legacy-symlink-");
const workspaceRoot = await temporaryRoot("cph-legacy-target-"); const workspaceRoot = await temporaryRoot("cph-legacy-target-");