This commit is contained in:
张成
2026-03-24 16:07:02 +08:00
commit aa8eaa6ccd
121 changed files with 34042 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
const baseModel = require("../../middleware/baseModel");
const tokenLogic = require("./biz_token_logic");
const usageSvc = require("./biz_usage_service");
function featureAllowed(plan, feature) {
if (!feature) return true;
const feats = plan.enabled_features;
if (feats == null) return true;
if (Array.isArray(feats)) return feats.includes(feature);
if (typeof feats === "object") {
return feats[feature] === true || feats[feature] === 1 || feats[feature] === "1";
}
return false;
}
function normalizeUsageDelta(raw) {
if (!raw || typeof raw !== "object") return {};
return {
msg: usageSvc.num(raw.msg ?? raw.msg_count),
mass: usageSvc.num(raw.mass ?? raw.mass_count),
friend: usageSvc.num(raw.friend ?? raw.friend_count),
sns: usageSvc.num(raw.sns ?? raw.sns_count),
active_user: usageSvc.num(raw.active_user ?? raw.active_user_count),
};
}
function hasPositiveDelta(delta) {
return Object.values(delta).some((v) => usageSvc.num(v) > 0);
}
/**
* 对外鉴权Token + 用户 + 有效订阅 + 功能点 + 可选用量上报与额度
* body: { token, feature?, usage_delta?: { msg?, mass?, ... } }
*/
async function verifyRequest(body) {
const { token, feature } = body || {};
if (!token) {
return { ok: false, error_code: "TOKEN_INVALID", message: "缺少 token" };
}
const hash = tokenLogic.hashPlainToken(token);
const row = await baseModel.biz_api_token.findOne({ where: { token_hash: hash } });
if (!row) {
return { ok: false, error_code: "TOKEN_INVALID", message: "Token 不存在" };
}
if (row.status === "revoked") {
return { ok: false, error_code: "TOKEN_REVOKED", message: "Token 已吊销" };
}
const now = new Date();
if (new Date(row.expire_at) < now) {
return { ok: false, error_code: "TOKEN_EXPIRED", message: "Token 已过期" };
}
const user = await baseModel.biz_user.findByPk(row.user_id);
if (!user || user.status !== "active") {
return { ok: false, error_code: "SUBSCRIPTION_INACTIVE", message: "用户不可用" };
}
const sub = await tokenLogic.findActiveSubscriptionForUser(row.user_id);
if (!sub) {
return { ok: false, error_code: "SUBSCRIPTION_INACTIVE", message: "无有效订阅" };
}
const plan = await baseModel.biz_plan.findByPk(sub.plan_id);
if (!plan || plan.status !== "active") {
return { ok: false, error_code: "SUBSCRIPTION_INACTIVE", message: "套餐不可用" };
}
if (feature && !featureAllowed(plan, feature)) {
return { ok: false, error_code: "FEATURE_NOT_ALLOWED", message: "功能未在套餐内" };
}
const statMonth = usageSvc.currentStatMonth();
let usageRow = await usageSvc.getOrCreateUsage(row.user_id, sub.plan_id, statMonth);
const delta = normalizeUsageDelta(body.usage_delta || body.usage_report);
if (hasPositiveDelta(delta)) {
const q = usageSvc.checkQuotaAfterDelta(plan, usageRow, delta);
if (!q.ok) {
return { ok: false, error_code: q.error_code || "QUOTA_EXCEEDED", message: q.message || "额度不足" };
}
usageRow = await usageSvc.applyDelta(row.user_id, sub.plan_id, statMonth, delta);
}
await row.update({ last_used_at: now });
return {
ok: true,
context: {
user_id: row.user_id,
plan_id: sub.plan_id,
subscription_id: sub.id,
token_id: row.id,
stat_month: statMonth,
usage_snapshot: {
msg_count: usageSvc.num(usageRow.msg_count),
mass_count: usageSvc.num(usageRow.mass_count),
friend_count: usageSvc.num(usageRow.friend_count),
sns_count: usageSvc.num(usageRow.sns_count),
active_user_count: usageSvc.num(usageRow.active_user_count),
},
},
};
}
module.exports = { verifyRequest };