import "server-only"; import type { Account } from "@prisma/client"; import { getActiveAccountProfile } from "@/lib/account-context"; import { assertAccountOwnedByUser } from "@/lib/auth/accounts"; import { prisma } from "@/lib/db"; import { DEFAULT_SEARCH_SOURCE_MODE, parseSearchSourceMode, type SearchSourceMode, } from "@/lib/search/source-mode"; export interface AccountConnectionSettings { searchViaApi: boolean; searchSourceMode: SearchSourceMode; publishViaApi: boolean; devMode: boolean; scrapeReplies: boolean; repliesPerPost: number; publishHeaded: boolean; playwrightDebug: boolean; } export function fromAccountPublic(settings: AccountConnectionSettings) { return settings; } export const DEFAULT_ACCOUNT_CONNECTION: AccountConnectionSettings = { searchViaApi: false, searchSourceMode: DEFAULT_SEARCH_SOURCE_MODE, publishViaApi: false, devMode: true, scrapeReplies: true, repliesPerPost: 10, publishHeaded: false, playwrightDebug: false, }; function fromAccount(account: Account): AccountConnectionSettings { return { searchViaApi: account.searchViaApi, searchSourceMode: parseSearchSourceMode(account.searchSourceMode), publishViaApi: account.publishViaApi, devMode: account.devMode, scrapeReplies: account.scrapeReplies, repliesPerPost: account.repliesPerPost, publishHeaded: account.publishHeaded, playwrightDebug: account.playwrightDebug, }; } /** 將舊版使用者層級連線設定一次性複製到各經營帳號。失敗時略過,不阻擋連線頁載入。 */ export async function migrateUserConnectionSettingsIfNeeded(userId: string) { try { const settings = await prisma.setting.findUnique({ where: { userId } }); if (!settings || settings.connectionMigrated) return; await prisma.account.updateMany({ where: { userId }, data: { searchViaApi: settings.searchViaApi, publishViaApi: settings.publishViaApi, devMode: settings.devMode, scrapeReplies: settings.scrapeReplies, repliesPerPost: settings.repliesPerPost, publishHeaded: settings.publishHeaded, playwrightDebug: settings.playwrightDebug, }, }); await prisma.setting.update({ where: { userId }, data: { connectionMigrated: true }, }); } catch (error) { console.warn("[connection-migrate] skipped:", error); } } export async function getAccountConnectionSettings( accountId: string ): Promise { const account = await prisma.account.findUnique({ where: { id: accountId } }); if (!account) return DEFAULT_ACCOUNT_CONNECTION; return fromAccount(account); } export async function getActiveAccountConnectionSettings(): Promise { const account = await getActiveAccountProfile(); if (!account) return DEFAULT_ACCOUNT_CONNECTION; if (account.userId) { await migrateUserConnectionSettingsIfNeeded(account.userId); const fresh = await prisma.account.findUnique({ where: { id: account.id } }); if (fresh) return fromAccount(fresh); } return fromAccount(account); } export async function updateActiveAccountConnectionSettings( userId: string, patch: Partial ) { await migrateUserConnectionSettingsIfNeeded(userId); const user = await prisma.user.findUnique({ where: { id: userId }, select: { activeAccountId: true }, }); if (!user?.activeAccountId) { throw new Error("請先建立並選擇一個經營帳號"); } await assertAccountOwnedByUser(userId, user.activeAccountId); const account = await prisma.account.update({ where: { id: user.activeAccountId }, data: { ...(patch.searchViaApi !== undefined && { searchViaApi: patch.searchViaApi }), ...(patch.searchSourceMode !== undefined && { searchSourceMode: parseSearchSourceMode(patch.searchSourceMode), }), ...(patch.publishViaApi !== undefined && { publishViaApi: patch.publishViaApi }), ...(patch.devMode !== undefined && { devMode: patch.devMode }), ...(patch.scrapeReplies !== undefined && { scrapeReplies: patch.scrapeReplies }), ...(patch.repliesPerPost !== undefined && { repliesPerPost: patch.repliesPerPost }), ...(patch.publishHeaded !== undefined && { publishHeaded: patch.publishHeaded }), ...(patch.playwrightDebug !== undefined && { playwrightDebug: patch.playwrightDebug }), }, }); return { account }; }