From 1e3940bd8e751f5fe96588ac400b41d99bd48bf7 Mon Sep 17 00:00:00 2001 From: Ike Saunders Date: Tue, 26 Nov 2024 17:22:15 -0500 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20CF=20images=20API=20enhancements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adminSiteClient/ImagesIndexPage.tsx | 39 +++++----- adminSiteServer/apiRouter.ts | 71 +++++++------------ .../types/src/dbTypes/Images.ts | 1 + 3 files changed, 46 insertions(+), 65 deletions(-) diff --git a/adminSiteClient/ImagesIndexPage.tsx b/adminSiteClient/ImagesIndexPage.tsx index dd07ba357e6..2a9c2b58058 100644 --- a/adminSiteClient/ImagesIndexPage.tsx +++ b/adminSiteClient/ImagesIndexPage.tsx @@ -24,7 +24,7 @@ type ImageEditorApi = { patch: Partial ) => void deleteImage: (image: DbEnrichedImage) => void - getImages: () => Promise + getImages: () => void } function AltTextEditor({ @@ -164,7 +164,7 @@ function ImageUploadButton({ setImages, admin, }: { - setImages: (images: DbEnrichedImage[]) => void + setImages: React.Dispatch> admin: Admin }) { function uploadImage({ file }: { file: string | Blob | RcFile }) { @@ -180,13 +180,12 @@ function ImageUploadButton({ type: file.type, } - const response = await admin.requestJSON( - "/api/image", - payload, - "POST" - ) + const { image } = await admin.requestJSON<{ + sucess: true + image: DbEnrichedImage + }>("/api/image", payload, "POST") - setImages(response.images) + setImages((images) => [image, ...images]) } reader.readAsDataURL(file) } @@ -206,25 +205,23 @@ export function ImageIndexPage() { const api = useMemo( (): ImageEditorApi => ({ deleteImage: async (image) => { - const response = await admin.requestJSON( - `/api/images/${image.id}`, - {}, - "DELETE" - ) - setImages(response.images) + await admin.requestJSON(`/api/images/${image.id}`, {}, "DELETE") + setImages((images) => images.filter((i) => i.id !== image.id)) }, getImages: async () => { - const json = await admin.getJSON("/api/images.json") + const json = await admin.getJSON<{ + images: DbEnrichedImage[] + }>("/api/images.json") setImages(json.images) - return json.images }, patchImage: async (image, patch) => { - const response = await admin.requestJSON( - `/api/images/${image.id}`, - patch, - "PATCH" + const response = await admin.requestJSON<{ + success: true + image: DbEnrichedImage + }>(`/api/images/${image.id}`, patch, "PATCH") + setImages((images) => + images.map((i) => (i.id === image.id ? response.image : i)) ) - setImages(response.images) }, }), [admin] diff --git a/adminSiteServer/apiRouter.ts b/adminSiteServer/apiRouter.ts index 97788c4d294..d499e71fbff 100644 --- a/adminSiteServer/apiRouter.ts +++ b/adminSiteServer/apiRouter.ts @@ -3122,43 +3122,35 @@ postRouteWithRWTransaction(apiRouter, "/image", async (req, res, trx) => { } } - await db.knexRaw( - trx, - `-- sql - INSERT INTO images - (filename, originalWidth, originalHeight, cloudflareId, defaultAlt, googleId, updatedAt) - VALUES - (?, ?, ?, ?, ?, ?, ?)`, - [ - filename, - dimensions.width, - dimensions.height, - cloudflareId, - // TODO: make defaultAlt nullable - "Default alt text", - // TODO: drop googleId - String(Math.random()).slice(2), - new Date().getTime(), - ] - ) + await trx("images").insert({ + filename, + originalWidth: dimensions.width, + originalHeight: dimensions.height, + cloudflareId, + // TODO: make defaultAlt nullable + defaultAlt: "Default alt text", + // TODO: drop googleId + googleId: String(Math.random()).slice(2), + updatedAt: new Date().getTime(), + }) - const images = await db.getCloudflareImages(trx) + const image = await trx("images") + .where("cloudflareId", "=", cloudflareId) + .first() return { success: true, - images, + image, } }) // Update alt text via patch patchRouteWithRWTransaction(apiRouter, "/images/:id", async (req, res, trx) => { const { id } = req.params - const image = await db.knexRawFirst( - trx, - `-- sql - SELECT * FROM images WHERE id = ?`, - [id] - ) + + const image = await trx("images") + .where("id", "=", id) + .first() if (!image) { throw new JsonError(`No image found for id ${id}`, 404) @@ -3173,11 +3165,13 @@ patchRouteWithRWTransaction(apiRouter, "/images/:id", async (req, res, trx) => { await trx("images").where({ id }).update(patch) - const images = await db.getCloudflareImages(trx) + const updated = await trx("images") + .where("id", "=", id) + .first() return { success: true, - images, + image: updated, } }) @@ -3187,12 +3181,9 @@ deleteRouteWithRWTransaction( async (req, res, trx) => { const { id } = req.params - const image = await db.knexRawFirst<{ cloudflareId: string }>( - trx, - `-- sql - SELECT cloudflareId FROM images WHERE id = ?`, - [id] - ) + const image = await trx("images") + .where("id", "=", id) + .first() if (!image) { throw new JsonError(`No image found for id ${id}`, 404) @@ -3216,18 +3207,10 @@ deleteRouteWithRWTransaction( throw new JsonError(JSON.stringify(response.errors)) } - await db.knexRaw( - trx, - `-- sql - DELETE FROM images WHERE id = ?`, - [id] - ) - - const images = await db.getCloudflareImages(trx) + await trx("images").where({ id }).delete() return { success: true, - images, } } ) diff --git a/packages/@ourworldindata/types/src/dbTypes/Images.ts b/packages/@ourworldindata/types/src/dbTypes/Images.ts index 15154d100a1..702415b33d6 100644 --- a/packages/@ourworldindata/types/src/dbTypes/Images.ts +++ b/packages/@ourworldindata/types/src/dbTypes/Images.ts @@ -1,5 +1,6 @@ export const ImagesTableName = "images" export interface DbInsertImage { + googleId: string defaultAlt: string filename: string id?: number