8 changed files with 188 additions and 42 deletions
@ -0,0 +1,48 @@ |
|||
import { NextRequest, NextResponse } from "next/server"; |
|||
import { getRequestToken } from "@/app/api/_auth"; |
|||
|
|||
const UPSTREAM_PRIVACY_POLICY_LATEST_PATH = "/api_client/content/privacyPolicy/latest"; |
|||
|
|||
function getPopiBaseUrl(request: NextRequest): string { |
|||
const baseUrl = |
|||
process.env.POPIART_API_BASE_URL || |
|||
process.env.NEXT_PUBLIC_APP_URL || |
|||
request.nextUrl.origin; |
|||
return baseUrl.replace(/\/+$/, ""); |
|||
} |
|||
|
|||
export async function GET(request: NextRequest) { |
|||
const key = request.nextUrl.searchParams.get("key")?.trim(); |
|||
if (!key) { |
|||
return NextResponse.json( |
|||
{ status: "4000", message: "key is required" }, |
|||
{ status: 400 }, |
|||
); |
|||
} |
|||
|
|||
const upstreamUrl = new URL(getPopiBaseUrl(request) + UPSTREAM_PRIVACY_POLICY_LATEST_PATH); |
|||
upstreamUrl.searchParams.set("key", key); |
|||
|
|||
const headers: Record<string, string> = { |
|||
Accept: "application/json", |
|||
}; |
|||
const token = getRequestToken(request); |
|||
if (token) { |
|||
headers.Authorization = `Bearer ${token}`; |
|||
headers.token = token; |
|||
} |
|||
|
|||
const upstream = await fetch(upstreamUrl, { |
|||
method: "GET", |
|||
headers, |
|||
cache: "no-store", |
|||
}); |
|||
|
|||
const body = await upstream.text(); |
|||
return new NextResponse(body, { |
|||
status: upstream.status, |
|||
headers: { |
|||
"Content-Type": upstream.headers.get("Content-Type") || "application/json", |
|||
}, |
|||
}); |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
|
|||
|
|||
/** 内容协议 key:使用说明 */ |
|||
export const PRIVACY_POLICY_KEY_USAGE_TUTORIAL = "web.usageTutorial"; |
|||
/** 内容协议 key:AI 功能使用须知 */ |
|||
export const PRIVACY_POLICY_KEY_AI_USE_NOTICE = "web.aiUseNotice"; |
|||
/** 内容协议 key:用户协议 */ |
|||
export const PRIVACY_POLICY_KEY_USER_TERMS = "web.userTerms"; |
|||
/** 内容协议 key:隐私政策 */ |
|||
export const PRIVACY_POLICY_KEY_PRIVACY_POLICY = "web.privacyPolicy"; |
|||
/** 内容协议 key:“Popi.art”付费服务协议 */ |
|||
export const PRIVACY_POLICY_KEY_PAYMENT_TERMS = "web.paymentTerms"; |
|||
/** 内容协议 key:Popi 存证协议 */ |
|||
export const PRIVACY_POLICY_KEY_EVIDENCE_PRESERVATION = "web.popiartEvidencePreservationAgreement"; |
|||
/** 内容协议 key:Popi Future Creator 计划用户服务协议 */ |
|||
export const PRIVACY_POLICY_KEY_FUTURE_CREATOR = "web.futureCreatorUserServiceAgreement"; |
|||
|
|||
export interface GetLatestPrivacyPolicyParams { |
|||
key: string; |
|||
} |
|||
|
|||
export async function getLatestPrivacyPolicy({ key }: GetLatestPrivacyPolicyParams): Promise<unknown> { |
|||
const params = new URLSearchParams({ key }); |
|||
const response = await fetch(`/api/content/privacy-policy/latest?${params.toString()}`, { |
|||
method: "GET", |
|||
}); |
|||
|
|||
const payload = (await response.json().catch(() => null)) as unknown; |
|||
if (!response.ok) { |
|||
const message = |
|||
typeof payload === "object" && |
|||
payload !== null && |
|||
"message" in payload && |
|||
typeof payload.message === "string" |
|||
? payload.message |
|||
: "Failed to fetch latest privacy policy."; |
|||
throw new Error(message); |
|||
} |
|||
|
|||
return payload; |
|||
} |
|||
interface PrivacyPolicyItem { |
|||
id: number; |
|||
title: string; |
|||
key: string; |
|||
type: number; |
|||
content: string; |
|||
status: number; |
|||
} |
|||
|
|||
interface PrivacyPolicyResponse { |
|||
data?: PrivacyPolicyItem; |
|||
message?: string; |
|||
status?: string; |
|||
} |
|||
|
|||
/** 按 key 拉取最新协议/说明,type 为 2 时在新标签页打开 content 链接 */ |
|||
export async function openLatestPrivacyPolicyLink(key: string): Promise<void> { |
|||
const res = (await getLatestPrivacyPolicy({ key })) as PrivacyPolicyResponse; |
|||
if (res.status && res.status !== "0000") { |
|||
throw new Error(res.message || "Failed to fetch latest privacy policy."); |
|||
} |
|||
const item = res.data; |
|||
if (!item?.content || item.type !== 2) { |
|||
throw new Error(res.message || "Latest privacy policy link is unavailable."); |
|||
} |
|||
window.open(item.content, "_blank", "noopener,noreferrer"); |
|||
} |
|||
Loading…
Reference in new issue