mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 06:15:39 -04:00
drizzle-orm/bun-sqlite is fully synchronous — all queries return values directly, not promises. Remove await from all db calls, drop async from functions that no longer need it, simplify Promise.all patterns that wrapped sync operations, and fix setSetting() which was missing .run() (previously masked by await triggering execution via thenable). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
140 lines
3.4 KiB
TypeScript
140 lines
3.4 KiB
TypeScript
"use server";
|
|
|
|
import crypto from "node:crypto";
|
|
import { and, eq } from "drizzle-orm";
|
|
import { headers } from "next/headers";
|
|
import { auth } from "@/lib/auth/server";
|
|
import { db } from "@/lib/db/client";
|
|
import { webhookConnections } from "@/lib/db/schema";
|
|
import { setSetting } from "@/lib/services/settings";
|
|
|
|
async function getSession() {
|
|
const session = await auth.api.getSession({ headers: await headers() });
|
|
if (!session) throw new Error("Unauthorized");
|
|
return session;
|
|
}
|
|
|
|
export async function saveWebhookConnection(
|
|
provider: "plex" | "jellyfin",
|
|
mediaServerUsername: string,
|
|
enabled?: boolean,
|
|
) {
|
|
const session = await getSession();
|
|
|
|
if (!["plex", "jellyfin"].includes(provider)) {
|
|
throw new Error("Invalid provider");
|
|
}
|
|
if (!mediaServerUsername?.trim()) {
|
|
throw new Error("Media server username is required");
|
|
}
|
|
|
|
const existing = db
|
|
.select()
|
|
.from(webhookConnections)
|
|
.where(
|
|
and(
|
|
eq(webhookConnections.userId, session.user.id),
|
|
eq(webhookConnections.provider, provider),
|
|
),
|
|
)
|
|
.get();
|
|
|
|
if (existing) {
|
|
const connection = db
|
|
.update(webhookConnections)
|
|
.set({
|
|
mediaServerUsername: mediaServerUsername.trim(),
|
|
enabled: typeof enabled === "boolean" ? enabled : existing.enabled,
|
|
})
|
|
.where(eq(webhookConnections.id, existing.id))
|
|
.returning()
|
|
.get();
|
|
return {
|
|
...connection,
|
|
lastEventAt: connection.lastEventAt?.toISOString() ?? null,
|
|
createdAt: connection.createdAt.toISOString(),
|
|
};
|
|
}
|
|
|
|
const token = crypto.randomBytes(32).toString("hex");
|
|
const now = new Date();
|
|
|
|
const connection = db
|
|
.insert(webhookConnections)
|
|
.values({
|
|
userId: session.user.id,
|
|
provider,
|
|
token,
|
|
mediaServerUsername: mediaServerUsername.trim(),
|
|
enabled: true,
|
|
createdAt: now,
|
|
})
|
|
.returning()
|
|
.get();
|
|
|
|
return {
|
|
...connection,
|
|
lastEventAt: connection.lastEventAt?.toISOString() ?? null,
|
|
createdAt: connection.createdAt.toISOString(),
|
|
};
|
|
}
|
|
|
|
export async function deleteWebhookConnection(provider: "plex" | "jellyfin") {
|
|
const session = await getSession();
|
|
|
|
if (!["plex", "jellyfin"].includes(provider)) {
|
|
throw new Error("Invalid provider");
|
|
}
|
|
|
|
db.delete(webhookConnections)
|
|
.where(
|
|
and(
|
|
eq(webhookConnections.userId, session.user.id),
|
|
eq(webhookConnections.provider, provider),
|
|
),
|
|
)
|
|
.run();
|
|
}
|
|
|
|
export async function regenerateWebhookToken(provider: "plex" | "jellyfin") {
|
|
const session = await getSession();
|
|
|
|
if (!["plex", "jellyfin"].includes(provider)) {
|
|
throw new Error("Invalid provider");
|
|
}
|
|
|
|
const newToken = crypto.randomBytes(32).toString("hex");
|
|
|
|
const connection = db
|
|
.update(webhookConnections)
|
|
.set({ token: newToken })
|
|
.where(
|
|
and(
|
|
eq(webhookConnections.userId, session.user.id),
|
|
eq(webhookConnections.provider, provider),
|
|
),
|
|
)
|
|
.returning()
|
|
.get();
|
|
|
|
if (!connection) {
|
|
throw new Error("Connection not found");
|
|
}
|
|
|
|
return {
|
|
...connection,
|
|
lastEventAt: connection.lastEventAt?.toISOString() ?? null,
|
|
createdAt: connection.createdAt.toISOString(),
|
|
};
|
|
}
|
|
|
|
export async function toggleRegistration(open: boolean) {
|
|
const session = await getSession();
|
|
|
|
if (session.user.role !== "admin") {
|
|
throw new Error("Forbidden");
|
|
}
|
|
|
|
setSetting("registrationOpen", String(open));
|
|
}
|