122 lines
2.9 KiB
TypeScript
122 lines
2.9 KiB
TypeScript
import { maybeAuthorizationMiddleware } from "#lib/middleware/authorization.js";
|
|
import { prisma } from "#lib/server/prisma.js";
|
|
import { defineApiRoute, APIError } from "astro-typesafe-api/server";
|
|
import { z } from "astro:content";
|
|
import isBase64 from "is-base64";
|
|
import { IDWithPrefix } from "#components/Ausweis/types.js";
|
|
import { BildSchema } from "src/generated/zod/bild.js";
|
|
import sharp from "sharp";
|
|
import { PutObjectCommand } from "@aws-sdk/client-s3";
|
|
import { s3Client } from "#lib/s3.js";
|
|
import { generateIDWithPrefix } from "#lib/db.js";
|
|
import { VALID_UUID_PREFIXES } from "#lib/constants.js";
|
|
import { logger } from "#lib/logger.js";
|
|
|
|
export const PUT = defineApiRoute({
|
|
input: BildSchema.pick({
|
|
kategorie: true,
|
|
name: true,
|
|
}).merge(
|
|
z.object({
|
|
data: z.string(),
|
|
})
|
|
),
|
|
output: z.object({
|
|
id: z.string({ description: "Die id des Bildes." }),
|
|
}),
|
|
middleware: maybeAuthorizationMiddleware,
|
|
async fetch(input, context, user) {
|
|
const data = input.data;
|
|
|
|
if (!isBase64(data, { mimeRequired: true })) {
|
|
throw new APIError({
|
|
code: "BAD_REQUEST",
|
|
message: "Das Bild ist nicht base64.",
|
|
});
|
|
}
|
|
|
|
const dataWithoutPrefix = data.replace(/^data:image\/\w+;base64,/, "");
|
|
const buffer = Buffer.from(dataWithoutPrefix, "base64");
|
|
|
|
const id = generateIDWithPrefix(9, VALID_UUID_PREFIXES.Bild);
|
|
|
|
const bild = await prisma.bild.create({
|
|
data: {
|
|
id,
|
|
kategorie: input.kategorie,
|
|
name: input.name,
|
|
benutzer_id: user ? user.id : null,
|
|
},
|
|
});
|
|
|
|
try {
|
|
// Wir optimieren das Bild und konvertieren es in JPEG
|
|
const optimizedBuffer = await sharp(buffer)
|
|
.jpeg({ quality: 80 })
|
|
.toBuffer();
|
|
|
|
const command = new PutObjectCommand({
|
|
Bucket: "ibc-images",
|
|
Key: `${id}.jpg`,
|
|
Body: optimizedBuffer,
|
|
ACL: "private",
|
|
});
|
|
|
|
const response = await s3Client.send(command);
|
|
} catch (e) {
|
|
// Bild wurde nicht gespeichert, wir löschen den Eintrag wieder
|
|
await prisma.bild.delete({
|
|
where: {
|
|
id,
|
|
},
|
|
});
|
|
logger.error("Fehler beim Speichern des Bildes in S3: " + e);
|
|
// Und geben einen Fehler zurück
|
|
throw new APIError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message: "Bild konnte nicht gespeichert werden.",
|
|
});
|
|
}
|
|
|
|
return {
|
|
id,
|
|
};
|
|
},
|
|
});
|
|
|
|
export const DELETE = defineApiRoute({
|
|
input: z.object({
|
|
id: IDWithPrefix,
|
|
}),
|
|
middleware: maybeAuthorizationMiddleware,
|
|
async fetch(input, context, user) {
|
|
try {
|
|
if (user) {
|
|
await prisma.bild.delete({
|
|
where: {
|
|
id: input.id,
|
|
OR: [{
|
|
benutzer_id: user.id
|
|
}, {
|
|
benutzer_id: null
|
|
}]
|
|
},
|
|
});
|
|
} else {
|
|
await prisma.bild.delete({
|
|
where: {
|
|
id: input.id,
|
|
aufnahme_id: null,
|
|
},
|
|
});
|
|
}
|
|
} catch (e) {
|
|
logger.error("Fehler beim Löschen des Bildes: " + e);
|
|
throw new APIError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message: "Bild konnte nicht gelöscht werden.",
|
|
});
|
|
}
|
|
},
|
|
});
|