From cb6dd0507194cc9c5ed45ba03644f7d6d57fde0e Mon Sep 17 00:00:00 2001 From: Tim Howitz Date: Thu, 22 May 2025 17:59:20 +0100 Subject: [PATCH] Fixed import artefacts and added imageName to artefact --- importersFixed.md | 6 ++ prisma/schema.prisma | 1 + public/Artefacts.csv | 2 +- src/app/api/import-artefacts/route.ts | 87 +++++++++++++++++++++++++++ src/app/api/import-artifacts/route.ts | 70 --------------------- 5 files changed, 95 insertions(+), 71 deletions(-) create mode 100644 importersFixed.md create mode 100644 src/app/api/import-artefacts/route.ts delete mode 100644 src/app/api/import-artifacts/route.ts diff --git a/importersFixed.md b/importersFixed.md new file mode 100644 index 0000000..9c49ae5 --- /dev/null +++ b/importersFixed.md @@ -0,0 +1,6 @@ +- [ ] Import users +- [x] Import artefacts +- [ ] Import earthquakes +- [ ] Import observatoies +- [ ] Import requests +- [ ] Import scientists diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 23d3a4c..86e5b9c 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -91,6 +91,7 @@ model Artefact { type String @db.VarChar(50) // Lava, Tephra, Ash, Soil warehouseArea String description String + imageName String earthquakeId Int earthquake Earthquake @relation(fields: [earthquakeId], references: [id]) creatorId Int? diff --git a/public/Artefacts.csv b/public/Artefacts.csv index 8532919..4a9c189 100644 --- a/public/Artefacts.csv +++ b/public/Artefacts.csv @@ -1,4 +1,4 @@ -Name,Type,WarehouseArea,Description,earthquakeID,Price,Required,PickedUp,Picture +Name,Type,WarehouseArea,Description,EarthquakeCode,Price,Required,PickedUp,Picture Echo Bomb,Lava,ShelvingAreaA,A dense glossy black volcanic bomb with minor vesicles.,EV-7.4-Mexico-00035,120,no,no,EchoBomb.PNG Silvershade Ash,Ash,ShelvingAreaD,Fine light-grey volcanic ash collected near a village.,EV-6.0-Iceland-00018,40,no,no,SilvershadeAsh.PNG Strata Core,Soil,LoggingArea,Soil core with visible stratification showing evidence of liquefaction.,ET-6.9-Brazil-00046,30,no,no,StrataCore.PNG diff --git a/src/app/api/import-artefacts/route.ts b/src/app/api/import-artefacts/route.ts new file mode 100644 index 0000000..01d2b08 --- /dev/null +++ b/src/app/api/import-artefacts/route.ts @@ -0,0 +1,87 @@ +import { parse } from "csv-parse/sync"; +import fs from "fs/promises"; +import { NextResponse } from "next/server"; +import path from "path"; +import { stringToBool } from "@utils/parsingUtils"; +import { prisma } from "@utils/prisma"; +import { getRandomNumber } from "@utils/maths"; + +const csvFilePath = path.resolve(process.cwd(), "public/artefacts.csv"); + +type CsvRow = { + Type: string; + Name: string; + Description: string; + WarehouseArea: string; + EarthquakeCode: string; + Required?: string; + Price: string; + PickedUp?: string; + Picture: string; +}; + +export async function POST() { + try { + const fileContent = await fs.readFile(csvFilePath, "utf8"); + const records: CsvRow[] = parse(fileContent, { + columns: true, + skip_empty_lines: true, + }); + + const failedImports: { row: CsvRow; reason: string }[] = []; + + const artefacts = await Promise.all( + records.map(async (row) => { + const earthquake = await prisma.earthquake.findUnique({ + where: { code: row.EarthquakeCode }, + }); + + const creators = await prisma.user.findMany({ + where: { + role: { in: ["SCIENTIST", "ADMIN"] }, + }, + }); + const randomCreator = creators.length > 0 ? creators[getRandomNumber(0, creators.length - 1)] : null; + + if (!earthquake || !randomCreator) { + failedImports.push({ row, reason: `Earthquake: ${earthquake}, RandomCreator: ${randomCreator}` }); + return undefined; + } + + return { + name: row.Name, + description: row.Description, + type: row.Type, + warehouseArea: row.WarehouseArea, + earthquakeId: earthquake.id, + required: stringToBool(row.Required, true), + shopPrice: row.Price && row.Price !== "" ? parseFloat(row.Price) : getRandomNumber(20, 500), + pickedUp: stringToBool(row.PickedUp, false), + creatorId: randomCreator.id, + purchasedById: null, + imageName: row.Picture, + }; + }) + ); + + const validArtefacts = artefacts.filter((artefact): artefact is NonNullable => artefact !== undefined); + + await prisma.artefact.createMany({ + data: validArtefacts, + }); + + if (failedImports.length > 0) { + console.warn("Failed imports:", failedImports); + await fs.writeFile(path.resolve(process.cwd(), "failed_imports_artefacts.json"), JSON.stringify(failedImports, null, 2)); + } + + return NextResponse.json({ + success: true, + count: validArtefacts.length, + failedCount: failedImports.length, + }); + } catch (error: any) { + console.error(error); + return NextResponse.json({ success: false, error: error.message }, { status: 500 }); + } +} diff --git a/src/app/api/import-artifacts/route.ts b/src/app/api/import-artifacts/route.ts deleted file mode 100644 index a5b2356..0000000 --- a/src/app/api/import-artifacts/route.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { parse } from "csv-parse/sync"; -import fs from "fs/promises"; -import { NextResponse } from "next/server"; -import path from "path"; - -import { PrismaClient } from "@prismaclient"; - -// CSV location -const csvFilePath = path.resolve(process.cwd(), "public/artefacts.csv"); -const prisma = new PrismaClient(); - -type CsvRow = { - Type: string; - Name: string; - Description: string; - WarehouseArea: string; - EarthquakeId: string; - Required?: string; - ShopPrice?: string; - PickedUp?: string; -}; - -function stringToBool(val: string | undefined, defaultValue: boolean = false): boolean { - if (!val) return defaultValue; - return /^true$/i.test(val.trim()); -} - -export async function POST() { - try { - // 1. Read file - const fileContent = await fs.readFile(csvFilePath, "utf8"); - - // 2. Parse CSV - const records: CsvRow[] = parse(fileContent, { - columns: true, - skip_empty_lines: true, - }); - - // 3. Map records to artefact input - const artefacts = records.map((row) => ({ - name: row.Name, - description: row.Description, - type: row.Type, - warehouseArea: row.WarehouseArea, - // todo get earthquakeId where code === row.EarthquakeCode - earthquakeId: parseInt(row.EarthquakeId, 10), - required: stringToBool(row.Required, true), // default TRUE - shopPrice: row.ShopPrice && row.ShopPrice !== "" ? parseFloat(row.ShopPrice) : null, - pickedUp: stringToBool(row.PickedUp, false), // default FALSE - // todo add random selection for creatorId - creatorId: null, - purchasedById: null, - })); - - // 4. Bulk insert - await prisma.artefact.createMany({ - data: artefacts, - }); - - return NextResponse.json({ - success: true, - count: artefacts.length, - }); - } catch (error: any) { - console.error(error); - return NextResponse.json({ success: false, error: error.message }, { status: 500 }); - } finally { - await prisma.$disconnect(); - } -}