haixunMaster/lib/account-connection-settings.ts

134 lines
4.4 KiB
TypeScript

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<AccountConnectionSettings> {
const account = await prisma.account.findUnique({ where: { id: accountId } });
if (!account) return DEFAULT_ACCOUNT_CONNECTION;
return fromAccount(account);
}
export async function getActiveAccountConnectionSettings(): Promise<AccountConnectionSettings> {
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<AccountConnectionSettings>
) {
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 };
}