chore(docker): .dockerignore angepasst; lokale Build-Schritte in Rebuild-Skripten; Doku/README zu production vs production-prebuilt aktualisiert
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { call, os } from "@orpc/server";
|
||||
import { z } from "zod";
|
||||
import { createKV } from "../lib/create-kv.js";
|
||||
import { assertOwner, sessionsKV } from "../lib/auth.js";
|
||||
import { assertOwner, getSessionFromCookies } from "../lib/auth.js";
|
||||
import { checkAdminRateLimit, getClientIP } from "../lib/rate-limiter.js";
|
||||
// Schema Definition
|
||||
const ReviewSchema = z.object({
|
||||
id: z.string(),
|
||||
@@ -75,20 +76,29 @@ const submitReview = os
|
||||
});
|
||||
// Admin Endpoint: approveReview
|
||||
const approveReview = os
|
||||
.input(z.object({ sessionId: z.string(), id: z.string() }))
|
||||
.handler(async ({ input }) => {
|
||||
.input(z.object({ id: z.string() }))
|
||||
.handler(async ({ input, context }) => {
|
||||
try {
|
||||
await assertOwner(input.sessionId);
|
||||
await assertOwner(context);
|
||||
// Admin Rate Limiting
|
||||
const ip = getClientIP(context.req.raw.headers);
|
||||
const session = await getSessionFromCookies(context);
|
||||
if (session) {
|
||||
const result = checkAdminRateLimit({ ip, userId: session.userId });
|
||||
if (!result.allowed) {
|
||||
throw new Error(`Zu viele Admin-Anfragen. Bitte versuche es in ${result.retryAfterSeconds} Sekunden erneut.`);
|
||||
}
|
||||
}
|
||||
const review = await reviewsKV.getItem(input.id);
|
||||
if (!review) {
|
||||
throw new Error("Bewertung nicht gefunden");
|
||||
}
|
||||
const session = await sessionsKV.getItem(input.sessionId).catch(() => undefined);
|
||||
const session2 = await getSessionFromCookies(context);
|
||||
const updatedReview = {
|
||||
...review,
|
||||
status: "approved",
|
||||
reviewedAt: new Date().toISOString(),
|
||||
reviewedBy: session?.userId || review.reviewedBy,
|
||||
reviewedBy: session2?.userId || review.reviewedBy,
|
||||
};
|
||||
await reviewsKV.setItem(input.id, updatedReview);
|
||||
return updatedReview;
|
||||
@@ -100,20 +110,29 @@ const approveReview = os
|
||||
});
|
||||
// Admin Endpoint: rejectReview
|
||||
const rejectReview = os
|
||||
.input(z.object({ sessionId: z.string(), id: z.string() }))
|
||||
.handler(async ({ input }) => {
|
||||
.input(z.object({ id: z.string() }))
|
||||
.handler(async ({ input, context }) => {
|
||||
try {
|
||||
await assertOwner(input.sessionId);
|
||||
await assertOwner(context);
|
||||
// Admin Rate Limiting
|
||||
const ip = getClientIP(context.req.raw.headers);
|
||||
const session = await getSessionFromCookies(context);
|
||||
if (session) {
|
||||
const result = checkAdminRateLimit({ ip, userId: session.userId });
|
||||
if (!result.allowed) {
|
||||
throw new Error(`Zu viele Admin-Anfragen. Bitte versuche es in ${result.retryAfterSeconds} Sekunden erneut.`);
|
||||
}
|
||||
}
|
||||
const review = await reviewsKV.getItem(input.id);
|
||||
if (!review) {
|
||||
throw new Error("Bewertung nicht gefunden");
|
||||
}
|
||||
const session = await sessionsKV.getItem(input.sessionId).catch(() => undefined);
|
||||
const session2 = await getSessionFromCookies(context);
|
||||
const updatedReview = {
|
||||
...review,
|
||||
status: "rejected",
|
||||
reviewedAt: new Date().toISOString(),
|
||||
reviewedBy: session?.userId || review.reviewedBy,
|
||||
reviewedBy: session2?.userId || review.reviewedBy,
|
||||
};
|
||||
await reviewsKV.setItem(input.id, updatedReview);
|
||||
return updatedReview;
|
||||
@@ -125,10 +144,19 @@ const rejectReview = os
|
||||
});
|
||||
// Admin Endpoint: deleteReview
|
||||
const deleteReview = os
|
||||
.input(z.object({ sessionId: z.string(), id: z.string() }))
|
||||
.handler(async ({ input }) => {
|
||||
.input(z.object({ id: z.string() }))
|
||||
.handler(async ({ input, context }) => {
|
||||
try {
|
||||
await assertOwner(input.sessionId);
|
||||
await assertOwner(context);
|
||||
// Admin Rate Limiting
|
||||
const ip = getClientIP(context.req.raw.headers);
|
||||
const session = await getSessionFromCookies(context);
|
||||
if (session) {
|
||||
const result = checkAdminRateLimit({ ip, userId: session.userId });
|
||||
if (!result.allowed) {
|
||||
throw new Error(`Zu viele Admin-Anfragen. Bitte versuche es in ${result.retryAfterSeconds} Sekunden erneut.`);
|
||||
}
|
||||
}
|
||||
await reviewsKV.removeItem(input.id);
|
||||
}
|
||||
catch (err) {
|
||||
@@ -160,12 +188,11 @@ const listPublishedReviews = os.handler(async () => {
|
||||
// Admin Endpoint: adminListReviews
|
||||
const adminListReviews = os
|
||||
.input(z.object({
|
||||
sessionId: z.string(),
|
||||
statusFilter: z.enum(["all", "pending", "approved", "rejected"]).optional().default("all"),
|
||||
}))
|
||||
.handler(async ({ input }) => {
|
||||
.handler(async ({ input, context }) => {
|
||||
try {
|
||||
await assertOwner(input.sessionId);
|
||||
await assertOwner(context);
|
||||
const allReviews = await reviewsKV.getAllItems();
|
||||
const filtered = input.statusFilter === "all"
|
||||
? allReviews
|
||||
@@ -188,11 +215,10 @@ const live = {
|
||||
}),
|
||||
adminListReviews: os
|
||||
.input(z.object({
|
||||
sessionId: z.string(),
|
||||
statusFilter: z.enum(["all", "pending", "approved", "rejected"]).optional().default("all"),
|
||||
}))
|
||||
.handler(async function* ({ input, signal }) {
|
||||
await assertOwner(input.sessionId);
|
||||
.handler(async function* ({ input, context, signal }) {
|
||||
await assertOwner(context);
|
||||
const allReviews = await reviewsKV.getAllItems();
|
||||
const filtered = input.statusFilter === "all"
|
||||
? allReviews
|
||||
|
Reference in New Issue
Block a user