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