1
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
const baseModel = require("../../middleware/baseModel");
|
||||
const { build_search_where, normalize_for_write } = require("../utils/query_helpers");
|
||||
const audit = require("../utils/biz_audit");
|
||||
const proxy_api_catalog = require("../service/biz_proxy_api_catalog");
|
||||
|
||||
module.exports = {
|
||||
"POST /biz_plan/page": async (ctx) => {
|
||||
@@ -105,4 +106,8 @@ module.exports = {
|
||||
});
|
||||
ctx.success({ rows });
|
||||
},
|
||||
/** 转发接口目录(与 swagger 一致),用于配置套餐 allowed_apis */
|
||||
"POST /biz_plan/proxy_api_catalog": async (ctx) => {
|
||||
ctx.success(proxy_api_catalog.buildCatalog());
|
||||
},
|
||||
};
|
||||
|
||||
54
api/service/biz_proxy_api_catalog.js
Normal file
54
api/service/biz_proxy_api_catalog.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const swagger = require("../../_docs/swagger.json");
|
||||
|
||||
const HTTP_METHODS = new Set(["get", "post", "put", "delete", "patch", "head", "options"]);
|
||||
|
||||
/**
|
||||
* 与 proxy_api.buildProxyRoutes 使用同一套 swagger.paths,供套餐「接口白名单」勾选
|
||||
* @returns {{ items: object[], groups: Record<string, object[]>, tags: string[] }}
|
||||
*/
|
||||
function buildCatalog() {
|
||||
const byPath = new Map();
|
||||
const paths = swagger.paths || {};
|
||||
|
||||
for (const [routePath, methods] of Object.entries(paths)) {
|
||||
if (!methods || typeof methods !== "object") continue;
|
||||
for (const [method, spec] of Object.entries(methods)) {
|
||||
if (!HTTP_METHODS.has(method.toLowerCase())) continue;
|
||||
if (!spec || typeof spec !== "object") continue;
|
||||
const tag = (spec.tags && spec.tags[0]) || "其他";
|
||||
const summary = spec.summary || spec.operationId || "";
|
||||
if (!byPath.has(routePath)) {
|
||||
byPath.set(routePath, {
|
||||
path: routePath,
|
||||
methods: new Set(),
|
||||
summary: summary || "",
|
||||
tag,
|
||||
});
|
||||
}
|
||||
const row = byPath.get(routePath);
|
||||
row.methods.add(method.toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
const items = Array.from(byPath.values())
|
||||
.map((x) => ({
|
||||
path: x.path,
|
||||
methods: Array.from(x.methods).sort(),
|
||||
summary: x.summary || "",
|
||||
tag: x.tag,
|
||||
}))
|
||||
.sort((a, b) => a.path.localeCompare(b.path));
|
||||
|
||||
/** @type {Record<string, object[]>} */
|
||||
const groups = {};
|
||||
for (const it of items) {
|
||||
if (!groups[it.tag]) groups[it.tag] = [];
|
||||
groups[it.tag].push(it);
|
||||
}
|
||||
|
||||
const tags = Object.keys(groups).sort((a, b) => a.localeCompare(b, "zh-CN"));
|
||||
|
||||
return { items, groups, tags };
|
||||
}
|
||||
|
||||
module.exports = { buildCatalog };
|
||||
@@ -135,12 +135,21 @@ async function incrementApiCallCount(userId, planId, statMonth) {
|
||||
*/
|
||||
function checkApiPathAllowed(plan, apiPath) {
|
||||
const allowed = plan.allowed_apis;
|
||||
// null / undefined:不限制接口
|
||||
if (allowed == null) return { ok: true };
|
||||
let list = allowed;
|
||||
if (typeof list === "string") {
|
||||
try { list = JSON.parse(list); } catch { return { ok: true }; }
|
||||
try {
|
||||
list = JSON.parse(list);
|
||||
} catch {
|
||||
return { ok: true };
|
||||
}
|
||||
}
|
||||
if (!Array.isArray(list)) return { ok: true };
|
||||
// 空数组:明确配置为「不允许任何转发接口」
|
||||
if (list.length === 0) {
|
||||
return { ok: false, error_code: "API_NOT_ALLOWED", message: "当前套餐未开放任何接口" };
|
||||
}
|
||||
if (!Array.isArray(list) || list.length === 0) return { ok: true };
|
||||
if (list.includes(apiPath)) return { ok: true };
|
||||
return { ok: false, error_code: "API_NOT_ALLOWED", message: `当前套餐不支持该接口: ${apiPath}` };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user