Files
image-prompt-studio/lib/quota.ts
2026-04-25 11:26:33 +08:00

102 lines
2.3 KiB
TypeScript

import "server-only";
import { toPublicUser } from "@/lib/auth";
import {
getSettingsSnapshot,
getUsageForUser,
listUserSummaries,
} from "@/lib/db";
import { getCurrentPeriodKey } from "@/lib/quota-core";
import type { AdminSnapshot, QuotaSnapshot, UserRecord } from "@/lib/types";
type QuotaUser = Pick<UserRecord, "id" | "role" | "monthlyQuota">;
export function getQuotaSnapshotForUser(
user: QuotaUser | null | undefined,
): QuotaSnapshot {
const periodKey = getCurrentPeriodKey();
if (!user || user.role === "admin") {
return {
periodKey,
limit: null,
used: user ? getUsageForUser(user.id, periodKey) : 0,
remaining: null,
isUnlimited: true,
};
}
const settings = getSettingsSnapshot();
const limit =
user.monthlyQuota === null
? settings.defaultMonthlyQuota
: user.monthlyQuota;
const used = getUsageForUser(user.id, periodKey);
return {
periodKey,
limit,
used,
remaining: Math.max(limit - used, 0),
isUnlimited: false,
};
}
export function assertCanGenerate(user: QuotaUser): QuotaSnapshot {
const quotaSnapshot = getQuotaSnapshotForUser(user);
const remaining = quotaSnapshot.remaining ?? 0;
if (!quotaSnapshot.isUnlimited && remaining <= 0) {
const error = new Error(
"本月额度已用完,请联系管理员调整额度。",
) as Error & {
statusCode?: number;
};
error.statusCode = 403;
throw error;
}
return quotaSnapshot;
}
export function buildAdminQuotaSummaries(): AdminSnapshot {
const settings = getSettingsSnapshot();
const periodKey = getCurrentPeriodKey();
const users = listUserSummaries(periodKey).map((user) => {
const publicUser = toPublicUser(user);
if (!publicUser) {
throw new Error("Failed to sanitize user record.");
}
if (user.role === "admin") {
return {
...publicUser,
usedThisPeriod: user.usedThisPeriod,
limit: null,
remaining: null,
isUnlimited: true,
};
}
const limit =
user.monthlyQuota === null
? settings.defaultMonthlyQuota
: user.monthlyQuota;
return {
...publicUser,
usedThisPeriod: user.usedThisPeriod,
limit,
remaining: Math.max(limit - user.usedThisPeriod, 0),
isUnlimited: false,
};
});
return {
settings,
periodKey,
users,
};
}