API Vollständig Umgezogen

This commit is contained in:
Moritz Utcke
2025-01-25 09:02:51 +07:00
parent 6f3ddedd96
commit 51fb7ad9b6
18 changed files with 329 additions and 113 deletions

View File

@@ -2,8 +2,7 @@ import { z } from "zod";
import moment from "moment";
import { prisma } from "@ibcornelsen/database/server";
import { encodeToken } from "../../../lib/auth/token.js";
import { TRPCError } from "@trpc/server";
import { defineApiRoute } from "astro-typesafe-api/server";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { TokenType } from "#lib/auth/types.js";
export const GET = defineApiRoute({
@@ -35,7 +34,7 @@ export const GET = defineApiRoute({
});
if (!response) {
throw new TRPCError({
throw new APIError({
code: "BAD_REQUEST",
message: "Der gegebene refresh token ist nicht gültig.",
});
@@ -48,7 +47,7 @@ export const GET = defineApiRoute({
id: response.id,
},
});
throw new TRPCError({
throw new APIError({
code: "BAD_REQUEST",
message: "Der gegebene refresh token ist nicht gültig.",
});
@@ -62,7 +61,7 @@ export const GET = defineApiRoute({
// id: response.id
// }
// })
// throw new TRPCError({ code: "BAD_REQUEST", message: "Der gegebene refresh token wurde von einer anderen IP-Adresse ausgestellt, aus Sicherheitsgründen haben wir uns entschieden diesen zu invalidieren." });
// throw new APIError({ code: "BAD_REQUEST", message: "Der gegebene refresh token wurde von einer anderen IP-Adresse ausgestellt, aus Sicherheitsgründen haben wir uns entschieden diesen zu invalidieren." });
// }
const user = await prisma.benutzer.findUnique({
@@ -78,7 +77,7 @@ export const GET = defineApiRoute({
id: response.id,
},
});
throw new TRPCError({
throw new APIError({
code: "BAD_REQUEST",
message: "Der gegebene refresh token ist nicht mehr gültig.",
});

View File

@@ -0,0 +1,84 @@
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
import { GebaeudeBilderSchema, prisma } from "@ibcornelsen/database/server";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "zod";
import isBase64 from "is-base64";
import { fileURLToPath } from "url";
import { writeFileSync } from "fs";
import { UUidWithPrefix } from "#components/Ausweis/types.js";
export const PATCH = defineApiRoute({
input: GebaeudeBilderSchema.pick({
kategorie: true,
}).merge(z.object({
base64: z.string()
})),
output: z.void(),
middleware: authorizationMiddleware,
async fetch(input, ctx, user) {
if (!UUidWithPrefix.safeParse(ctx.params.uid).success) {
throw new APIError({
code: "BAD_REQUEST",
message: "UID konnte nicht verifiziert werden."
})
}
const image = await prisma.gebaeudeBilder.findUnique({
where: {
uid: ctx.params.uid,
objekt: {
benutzer_id: user.id
}
}
})
if (!image) {
throw new APIError({
code: "BAD_REQUEST",
message: "Bild existiert nicht oder gehört einem anderen Benutzer."
})
}
const base64 = input.base64;
if (!isBase64(base64, { mimeRequired: true })) {
throw new APIError({
code: "BAD_REQUEST",
message: "Das Bild ist nicht base64.",
});
}
const dataWithoutPrefix = base64.replace(
/^data:image\/\w+;base64,/,
""
);
const buffer = Buffer.from(dataWithoutPrefix, "base64");
if (input.kategorie !== image.kategorie) {
await prisma.gebaeudeBilder.update({
where: {
id: image.id
},
data: {
kategorie: input.kategorie
}
});
}
const filePath = fileURLToPath(new URL(`../../../../../persistent/images/${image.uid}.webp`, import.meta.url));
try {
// Wir optimieren das Bild und konvertieren es in WebP
// TODO: Sharp scheint nicht zu funktionieren, wir müssen das nochmal testen
// const optimizedBuffer = await sharp(buffer).webp({ quality: 80 }).toArray();
writeFileSync(filePath, buffer)
} catch(e) {
// Und geben einen Fehler zurück
throw new APIError({
code: "INTERNAL_SERVER_ERROR",
message: "Bild konnte nicht gespeichert werden.",
});
}
},
})

View File

@@ -1,6 +1,6 @@
import { OptionalNullable, UUidWithPrefix, VerbrauchsausweisWohnenClient, ZodOverlap } from "#components/Ausweis/types.js";
import { exclude } from "#lib/exclude.js";
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma, VerbrauchsausweisWohnenSchema } from "@ibcornelsen/database/server";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "zod";
@@ -43,6 +43,101 @@ export const PATCH = defineApiRoute({
},
})
export const DELETE = defineApiRoute({
meta: {
description: "Storniert einen Ausweis"
},
headers: authorizationHeaders,
middleware: authorizationMiddleware,
async fetch(input, ctx, user) {
const { uid } = ctx.params;
if (!UUidWithPrefix.safeParse(uid).success) {
throw new APIError({
code: "BAD_REQUEST",
message: "UID konnte nicht verifiziert werden."
})
}
// Wir holen uns den Verbrauchsausweis
// Dieser MUSS mit dem Nutzer verknüpft sein.
const ausweis = await prisma.verbrauchsausweisWohnen.findUnique({
where: {
uid,
},
include: {
aufnahme: {
select: {
storniert: true
}
}
}
});
if (!ausweis) {
// Falls wir den Ausweis nicht finden können, werfen wir einen Fehler
throw new APIError({
code: "NOT_FOUND",
message: "Ausweis konnte nicht gefunden werden.",
});
}
// Wir dürfen den Ausweis nur stornieren, wenn er noch nicht ausgestellt wurde
// Außerdem müssen wir schauen, ob wir Admin oder der Besitzer des Ausweises sind.
if ((ausweis.benutzer_id !== user.id) && user.rolle !== "ADMIN") {
// Falls der Ausweis nicht dem Nutzer gehört, werfen wir einen Fehler
throw new APIError({
code: "FORBIDDEN",
message: "Ausweis gehört nicht dem Nutzer.",
});
}
// if (ausweis.erledigt) {
// // Falls der Ausweis bereits ausgestellt wurde, werfen wir einen Fehler
// throw new TRPCError({
// code: "BAD_REQUEST",
// message: "Ausweis wurde bereits ausgestellt.",
// });
// }
if (ausweis.aufnahme.storniert) {
// Falls der Ausweis bereits storniert ist, werfen wir einen Fehler
throw new APIError({
code: "BAD_REQUEST",
message: "Ausweis wurde bereits storniert.",
});
}
await prisma.aufnahme.update({
where: {
id: ausweis.aufnahme_id
},
data: {
storniert: true
}
})
// Wir erstellen ein Event, dass der Ausweis storniert wurde
// Dann können wir das in der Historie anzeigen
await prisma.event.create({
data: {
title: "Ausweis storniert",
description: ((user.rolle === "ADMIN") && (ausweis.benutzer_id !== user.id)) ? "Ausweis wurde von einem Administrator storniert." : "Ausweis wurde vom Besitzer storniert.",
benutzer: {
connect: {
id: user.id
}
},
aufnahme: {
connect: {
id: ausweis.aufnahme_id
}
}
}
})
},
})
export const GET = defineApiRoute({
meta: {
description: "Gibt ein spezifisches Gebäude des Benutzers zurück.",