diff --git a/src/routers/paintings.ts b/src/routers/paintings.ts index dae6090..e188116 100644 --- a/src/routers/paintings.ts +++ b/src/routers/paintings.ts @@ -1,14 +1,53 @@ -import { PrismaClient } from "@prisma/client" +import { PrismaClient, PaintingAuthor, Painting, Author } from "@prisma/client" import express, { RequestHandler } from "express" import { z } from "zod" import { getPaintingQuery } from "../utils/queries.js" import fs from "fs" -const paintingsRouter = express.Router() -// const prisma = new PrismaClient() +interface GraphQlPainting { + data: { + nodeQuery: { + entities: { + entityUuid: string + title: string + absolutePath: string + fieldOeuvreAuteurs: { + entity: { + fieldAuteurAuteur: { + entity: { + name: string + } + } + } + }[] + fieldVisuels: { + entity: { + publicUrl: string + } + }[] + fieldMusee: { + entity: { + name: string + } + } + }[] + } + } +} -const paintingParser = z +interface ParsedPainting { + image_url: string + name: string + link: string + musuem: string + author: string +} + +const paintingsRouter = express.Router() +const prisma = new PrismaClient() + +const paintingParamsParser = z .object({ uuid: z.string(), }) @@ -20,7 +59,18 @@ const randomParser = z }) .required() -async function fetchPainting(uuid: string): Promise { +function parseGraphQlPainting(painting: GraphQlPainting): ParsedPainting { + const graphQlPainting = painting.data.nodeQuery.entities[0] + return { + image_url: graphQlPainting.fieldVisuels[0].entity.publicUrl, + name: graphQlPainting.title, + link: graphQlPainting.absolutePath, + musuem: graphQlPainting.fieldMusee.entity.name, + author: graphQlPainting.fieldOeuvreAuteurs[0].entity.fieldAuteurAuteur.entity.name, + } +} + +function fetchPainting(uuid: string): Promise { return new Promise((resolve, reject) => { fetch("https://apicollections.parismusees.paris.fr/graphql", { method: "POST", @@ -35,32 +85,165 @@ async function fetchPainting(uuid: string): Promise { }) } -async function getRandomPaintings(limit: number): Promise { - const paintingsUUIDs = JSON.parse( - fs.readFileSync("src/assets/paintingsUUID.json", "utf8") - ) - const randomUUIDs = paintingsUUIDs.paintings - .sort(() => Math.random() - 0.5) - .slice(0, limit) +async function getRandomPaintings(limit: number): Promise<(Painting | null)[]> { + const paintingsUUIDs = JSON.parse(fs.readFileSync("src/assets/paintingsUUID.json", "utf8")) + const randomUUIDs = paintingsUUIDs.paintings.sort(() => Math.random() - 0.5).slice(0, limit) const paintings = [] for (const uuid of randomUUIDs) { - const painting = await fetchPainting(uuid) - paintings.push(painting) + const fetchedPainting = await fetchPainting(uuid) + const parsedPainting = parseGraphQlPainting(fetchedPainting) + + const painting = await getPainting(undefined, parsedPainting.name) + if (!painting) { + const createdPaintingAuthor = await createPainting(parsedPainting) + paintings.push(await getPainting(createdPaintingAuthor.painting_id, undefined)) + continue + } + + await updatePaintingIfNeeded(painting, parsedPainting) + paintings.push(await getPainting(undefined, parsedPainting.name)) } return paintings } +async function createPainting(painting: ParsedPainting): Promise { + return await prisma.paintingAuthor.create({ + data: { + painting: { + create: { + image_url: painting.image_url, + name: painting.name, + link: painting.link, + Musuem: { + connectOrCreate: { + where: { + name: painting.musuem, + }, + create: { + name: painting.musuem, + }, + }, + }, + }, + }, + author: { + connectOrCreate: { + where: { + fullname: painting.author, + }, + create: { + fullname: painting.author, + }, + }, + }, + }, + }) +} + +async function getPainting(id?: number, name?: string): Promise { + if (!id && !name) return null + + return await prisma.painting.findUnique({ + where: id ? { id } : { name }, + include: { PaintingAuthor: { select: { author: true } } }, + }) +} + +async function getPaintingAuthors(paintingId: number): Promise<(Author | null)[]> { + const paintingAuthors = ( + await prisma.painting.findUnique({ + where: { id: paintingId }, + include: { PaintingAuthor: true }, + }) + )?.PaintingAuthor + + if (!paintingAuthors) return [] + + const authors = [] + + for (const paintingAuthor of paintingAuthors) { + const author = await prisma.author.findUnique({ + where: { id: paintingAuthor.author_id }, + }) + authors.push(author) + } + + return authors +} + +async function updatePainting(id: number, painting: ParsedPainting): Promise { + return await prisma.painting.update({ + where: { + id: id, + }, + data: { + image_url: painting.image_url, + name: painting.name, + link: painting.link, + Musuem: { + connectOrCreate: { + where: { + name: painting.musuem, + }, + create: { + name: painting.musuem, + }, + }, + }, + }, + }) +} + +async function updatePaintingIfNeeded( + painting: Painting, + parsedPainting: ParsedPainting +): Promise { + const paintingMusuem = ( + await prisma.painting.findUnique({ + where: { + id: painting.id, + }, + select: { + Musuem: true, + }, + }) + )?.Musuem + const paintingAuthors = await getPaintingAuthors(painting.id) + + if ( + painting.image_url !== parsedPainting.image_url || + painting.name !== parsedPainting.name || + painting.link !== parsedPainting.link || + paintingMusuem?.name !== parsedPainting.musuem || + paintingAuthors?.[0]?.fullname !== parsedPainting.author + ) { + updatePainting(painting.id, parsedPainting) + } +} + const paintingRouterGet: RequestHandler = async (req, res) => { - const parsedPainting = paintingParser.safeParse(req.params) - if (!parsedPainting.success) { + const parsedPaintingParams = paintingParamsParser.safeParse(req.params) + if (!parsedPaintingParams.success) { res.status(400).send({ message: "Please provide valid painting UUID." }) return } - const painting = await fetchPainting(parsedPainting.data.uuid) - res.send({ painting }) + const fetchedPainting = await fetchPainting(parsedPaintingParams.data.uuid) + const parsedPainting = parseGraphQlPainting(fetchedPainting) + + const painting = await getPainting(undefined, parsedPainting.name) + if (!painting) { + const createdPaintingAuthor = await createPainting(parsedPainting) + res.send({ painting: await getPainting(createdPaintingAuthor.painting_id, undefined) }) + return + } + + await updatePaintingIfNeeded(painting, parsedPainting) + + res.send({ painting: await getPainting(undefined, parsedPainting.name) }) + return } const paintingRouterGetRandoms: RequestHandler = async (req, res) => { diff --git a/src/utils/queries.ts b/src/utils/queries.ts index 7b828d0..6b94119 100644 --- a/src/utils/queries.ts +++ b/src/utils/queries.ts @@ -9,7 +9,6 @@ export function getPaintingQuery(uuid: string) { ... on NodeOeuvre { title absolutePath - fieldUrlAlias fieldOeuvreAuteurs { entity { fieldAuteurAuteur { @@ -22,7 +21,6 @@ export function getPaintingQuery(uuid: string) { fieldVisuels { entity { name - vignette publicUrl } }