Rename the unified application to dashboard
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import { ZodError } from "zod";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { currentAccount } from "@/lib/account";
|
||||
import { trustedOrigin } from "@/lib/account-crypto";
|
||||
import { documentInput, parseDocumentXml } from "@/lib/guidance-input";
|
||||
import {
|
||||
discoverDocuments,
|
||||
publishDocument,
|
||||
resolveDocument,
|
||||
withdrawDocument,
|
||||
} from "@/lib/guidance-store";
|
||||
import { guidanceXml } from "@/content/guides/catalog";
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
res.setHeader("Cache-Control", "no-store");
|
||||
const path = req.query.path || [];
|
||||
if (!Array.isArray(path) || path.length > 1) return res.status(404).end();
|
||||
const id = path[0];
|
||||
try {
|
||||
if (req.method === "GET") {
|
||||
if (!id) {
|
||||
const author = req.query.author;
|
||||
if (
|
||||
author !== undefined &&
|
||||
(typeof author !== "string" ||
|
||||
!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
|
||||
author,
|
||||
))
|
||||
)
|
||||
return res.status(400).json({ error: "作者 ID 无效" });
|
||||
return res.json({ documents: await discoverDocuments(author) });
|
||||
}
|
||||
const revision = req.query.revision;
|
||||
if (
|
||||
revision !== undefined &&
|
||||
(typeof revision !== "string" ||
|
||||
!/^[1-9][0-9]{0,9}$/.test(revision) ||
|
||||
Number(revision) > 2147483647)
|
||||
)
|
||||
return res.status(400).json({ error: "版本无效" });
|
||||
const doc = await resolveDocument(
|
||||
id,
|
||||
revision === undefined ? undefined : Number(revision),
|
||||
);
|
||||
if (!doc) return res.status(404).json({ error: "文档或精确版本不存在" });
|
||||
if (req.query.format === "xml") {
|
||||
res.setHeader("Content-Type", "application/xml; charset=utf-8");
|
||||
return res.send(guidanceXml(doc));
|
||||
}
|
||||
return res.json({ document: doc });
|
||||
}
|
||||
if (!["POST", "DELETE"].includes(req.method || "")) {
|
||||
res.setHeader("Allow", "GET, POST, DELETE");
|
||||
return res.status(405).end();
|
||||
}
|
||||
const request = new Request(
|
||||
new URL(
|
||||
req.url || "/",
|
||||
process.env.ACCOUNT_PUBLIC_ORIGIN || "http://" + req.headers.host,
|
||||
),
|
||||
{
|
||||
headers: new Headers(
|
||||
Object.entries(req.headers).filter(
|
||||
([, v]) => typeof v === "string",
|
||||
) as [string, string][],
|
||||
),
|
||||
},
|
||||
);
|
||||
if (!trustedOrigin(request))
|
||||
return res.status(403).json({ error: "请求来源不受信任" });
|
||||
const user = await currentAccount(request);
|
||||
if (!user) return res.status(401).json({ error: "请先登录已验证邮箱账户" });
|
||||
if (req.method === "DELETE")
|
||||
return id && (await withdrawDocument(user.id, id))
|
||||
? res.json({ ok: true })
|
||||
: res.status(404).json({ error: "无权删除或不存在" });
|
||||
const input =
|
||||
typeof req.body === "string"
|
||||
? parseDocumentXml(req.body)
|
||||
: documentInput.parse(req.body);
|
||||
if (id === "preview") {
|
||||
const links = await Promise.all(
|
||||
input.links.map(async (l) => ({
|
||||
...l,
|
||||
resolved: !!(await resolveDocument(l.target, l.revision)),
|
||||
})),
|
||||
);
|
||||
return res.json({ document: input, xml: guidanceXml(input), links });
|
||||
}
|
||||
if (id && id !== input.id)
|
||||
return res.status(400).json({ error: "文档 ID 不匹配" });
|
||||
return res
|
||||
.status(201)
|
||||
.json({ document: await publishDocument(user.id, input) });
|
||||
} catch (e) {
|
||||
if (e instanceof ZodError)
|
||||
return res
|
||||
.status(400)
|
||||
.json({
|
||||
error: "输入不符合协议,请检查以下字段",
|
||||
fields: e.issues.slice(0, 12).map((i) => i.path.join(".") || "文档"),
|
||||
});
|
||||
const message = e instanceof Error ? e.message : "";
|
||||
if (message === "INVALID_ID")
|
||||
return res
|
||||
.status(400)
|
||||
.json({
|
||||
error: "文档 ID 必须以 user-你的账户ID- 开头,请使用编辑器生成的前缀",
|
||||
});
|
||||
if (message === "FORBIDDEN")
|
||||
return res.status(403).json({ error: "仅作者可编辑" });
|
||||
if (message === "CONFLICT" || (e as { code?: string }).code === "23505")
|
||||
return res
|
||||
.status(409)
|
||||
.json({ error: "版本冲突:请加载最新版本,已发布版本不可修改" });
|
||||
if (
|
||||
e instanceof Error &&
|
||||
(e.name === "ZodError" || /XML|实体|元素|属性|协议|链接/.test(message))
|
||||
)
|
||||
return res.status(400).json({ error: "输入不符合协议" });
|
||||
return res.status(503).json({ error: "文档服务暂不可用" });
|
||||
}
|
||||
}
|
||||
export const config = { api: { bodyParser: { sizeLimit: "128kb" } } };
|
||||
Reference in New Issue
Block a user