66 lines
2.0 KiB
TypeScript
66 lines
2.0 KiB
TypeScript
import { getServerSession } from "next-auth";
|
|
import { eq } from "drizzle-orm";
|
|
import { db } from "@/db";
|
|
import { users } from "@/db/schema";
|
|
import { authOptions } from "@/lib/auth/auth-options";
|
|
import { getSessionDiscordId, type SessionWithDiscord } from "@/lib/auth/auth";
|
|
import { createShare } from "@/lib/share/create";
|
|
import { ShareHttpError, shareErrorResponse } from "@/lib/share/http-error";
|
|
import { enforceShareRateLimit } from "@/lib/share/rate-limit";
|
|
import {
|
|
validateOptionalImage,
|
|
validateShareDescription,
|
|
validateShareText,
|
|
} from "@/lib/share/validation";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export async function POST(request: Request) {
|
|
try {
|
|
const session = await getServerSession(authOptions);
|
|
const discordId = getSessionDiscordId(session);
|
|
const userId = (session as SessionWithDiscord | null)?.user?.id;
|
|
if (!discordId || !userId) {
|
|
throw new ShareHttpError("Unauthorized", 401);
|
|
}
|
|
|
|
const formData = await request.formData();
|
|
const content = validateShareText(formData.get("text"));
|
|
const description = validateShareDescription(formData.get("description"));
|
|
const image = await validateOptionalImage(formData.get("image"));
|
|
|
|
await enforceShareRateLimit({
|
|
key: `sender:${discordId}`,
|
|
limit: 10,
|
|
windowSeconds: 60 * 60,
|
|
});
|
|
|
|
const [user] = await db
|
|
.select({ id: users.id, name: users.name, image: users.image })
|
|
.from(users)
|
|
.where(eq(users.id, userId))
|
|
.limit(1);
|
|
if (!user) throw new ShareHttpError("Unauthorized", 401);
|
|
|
|
const share = await createShare({
|
|
content,
|
|
description,
|
|
image,
|
|
source: "web",
|
|
author: {
|
|
userId: user.id,
|
|
discordId,
|
|
displayName: user.name || session?.user?.name || "Discord user",
|
|
avatarUrl: user.image || session?.user?.image || null,
|
|
},
|
|
});
|
|
|
|
return Response.json(
|
|
{ success: true, share: { id: share.id, url: `/share/${share.id}` } },
|
|
{ status: 201 }
|
|
);
|
|
} catch (error) {
|
|
return shareErrorResponse(error);
|
|
}
|
|
}
|