Spaces:
Running
Running
Rename session quota limit field
Browse files- src/admin.ts +3 -3
- src/analysis.ts +1 -1
- src/server.ts +5 -5
- src/subscriptions.ts +1 -1
src/admin.ts
CHANGED
|
@@ -71,7 +71,7 @@ export function registerAdminRoutes(app: Express) {
|
|
| 71 |
if (counts.error) throw new Error(`Unable to load user session counts: ${counts.error.message}`);
|
| 72 |
const planIds = [...new Set((subs.data ?? []).flatMap((row) => row.subscription_id ? [row.subscription_id] : []))];
|
| 73 |
const { data: plans, error: plansError } = planIds.length
|
| 74 |
-
? await supabaseAdmin.from("subscriptions").select("subscription_id,plan,price,player_limit,
|
| 75 |
: { data: [], error: null };
|
| 76 |
if (plansError) throw new Error(`Unable to load plan names: ${plansError.message}`);
|
| 77 |
const planMap = new Map((plans ?? []).map((plan) => [plan.subscription_id, plan]));
|
|
@@ -84,7 +84,7 @@ export function registerAdminRoutes(app: Express) {
|
|
| 84 |
return {
|
| 85 |
id: row.user_id, fname: row.fname, lname: row.lname, name: `${row.fname} ${row.lname}`.trim(),
|
| 86 |
email: row.email, academy: row.academy, role: row.role, imagePath: row.image_path, accountRole: row.account_role,
|
| 87 |
-
subscription: plan ? { id: plan.subscription_id, name: plan.plan, startDate: assignment?.startdate, endDate: assignment?.enddate, playerLimit: plan.player_limit, sessionLimit: plan.
|
| 88 |
usage: { players: assignment?.num_players ?? 0, sessions: assignment?.num_sessions ?? 0, totalSessions: sessionCounts.get(row.user_id) ?? 0 },
|
| 89 |
};
|
| 90 |
}) });
|
|
@@ -92,7 +92,7 @@ export function registerAdminRoutes(app: Express) {
|
|
| 92 |
|
| 93 |
app.get("/api/admin/plans", asyncRoute(async (req, res) => {
|
| 94 |
if (!await admin(req, res)) return;
|
| 95 |
-
const { data, error } = await supabaseAdmin.from("subscriptions").select("subscription_id,plan,price,player_limit,
|
| 96 |
if (error) throw new Error(`Unable to load plans: ${error.message}`);
|
| 97 |
return res.json({ plans: data ?? [] });
|
| 98 |
}));
|
|
|
|
| 71 |
if (counts.error) throw new Error(`Unable to load user session counts: ${counts.error.message}`);
|
| 72 |
const planIds = [...new Set((subs.data ?? []).flatMap((row) => row.subscription_id ? [row.subscription_id] : []))];
|
| 73 |
const { data: plans, error: plansError } = planIds.length
|
| 74 |
+
? await supabaseAdmin.from("subscriptions").select("subscription_id,plan,price,player_limit,session_limit").in("subscription_id", planIds)
|
| 75 |
: { data: [], error: null };
|
| 76 |
if (plansError) throw new Error(`Unable to load plan names: ${plansError.message}`);
|
| 77 |
const planMap = new Map((plans ?? []).map((plan) => [plan.subscription_id, plan]));
|
|
|
|
| 84 |
return {
|
| 85 |
id: row.user_id, fname: row.fname, lname: row.lname, name: `${row.fname} ${row.lname}`.trim(),
|
| 86 |
email: row.email, academy: row.academy, role: row.role, imagePath: row.image_path, accountRole: row.account_role,
|
| 87 |
+
subscription: plan ? { id: plan.subscription_id, name: plan.plan, startDate: assignment?.startdate, endDate: assignment?.enddate, playerLimit: plan.player_limit, sessionLimit: plan.session_limit } : null,
|
| 88 |
usage: { players: assignment?.num_players ?? 0, sessions: assignment?.num_sessions ?? 0, totalSessions: sessionCounts.get(row.user_id) ?? 0 },
|
| 89 |
};
|
| 90 |
}) });
|
|
|
|
| 92 |
|
| 93 |
app.get("/api/admin/plans", asyncRoute(async (req, res) => {
|
| 94 |
if (!await admin(req, res)) return;
|
| 95 |
+
const { data, error } = await supabaseAdmin.from("subscriptions").select("subscription_id,plan,price,player_limit,session_limit").order("price");
|
| 96 |
if (error) throw new Error(`Unable to load plans: ${error.message}`);
|
| 97 |
return res.json({ plans: data ?? [] });
|
| 98 |
}));
|
src/analysis.ts
CHANGED
|
@@ -57,7 +57,7 @@ export function analysisRouter(db: SupabaseClient, secret: string) {
|
|
| 57 |
.select("num_sessions").eq("user_id", userId).maybeSingle();
|
| 58 |
if (usageError) return res.status(503).json({ error: "Unable to check your session quota." });
|
| 59 |
const usedSessions = Number(usage?.num_sessions ?? 0);
|
| 60 |
-
const sessionLimit = subscription?.
|
| 61 |
if (sessionLimit !== null && usedSessions >= sessionLimit) {
|
| 62 |
return res.status(403).json({
|
| 63 |
error: "You have used all sessions included in this plan period. Renew or upgrade your plan to analyze another session.",
|
|
|
|
| 57 |
.select("num_sessions").eq("user_id", userId).maybeSingle();
|
| 58 |
if (usageError) return res.status(503).json({ error: "Unable to check your session quota." });
|
| 59 |
const usedSessions = Number(usage?.num_sessions ?? 0);
|
| 60 |
+
const sessionLimit = subscription?.session_limit == null ? null : Number(subscription.session_limit);
|
| 61 |
if (sessionLimit !== null && usedSessions >= sessionLimit) {
|
| 62 |
return res.status(403).json({
|
| 63 |
error: "You have used all sessions included in this plan period. Renew or upgrade your plan to analyze another session.",
|
src/server.ts
CHANGED
|
@@ -139,7 +139,7 @@ async function requireActiveSubscription(req: Request, res: Response) {
|
|
| 139 |
return null;
|
| 140 |
}
|
| 141 |
if (await userIsAdmin(current.user.id)) {
|
| 142 |
-
return { ...current, isAdmin: true, subscription: { player_limit: null,
|
| 143 |
}
|
| 144 |
const subscription = await activeSubscriptionFor(current.user.id, { refresh: true });
|
| 145 |
if (!subscription) {
|
|
@@ -169,7 +169,7 @@ app.get("/health", (_req, res) => res.json({ ok: true }));
|
|
| 169 |
app.get("/api/subscriptions", async (_req, res, next) => {
|
| 170 |
try {
|
| 171 |
const { data, error } = await supabaseAdmin.from("subscriptions")
|
| 172 |
-
.select("subscription_id,plan,price,player_limit,
|
| 173 |
.order("price", { ascending: true });
|
| 174 |
if (error) throw new Error(`Unable to load subscription plans: ${error.message}`);
|
| 175 |
const plans = (data ?? []).map((row) => ({
|
|
@@ -178,7 +178,7 @@ app.get("/api/subscriptions", async (_req, res, next) => {
|
|
| 178 |
name: row.plan,
|
| 179 |
monthlyPrice: Number(row.price),
|
| 180 |
playerLimit: row.player_limit == null ? null : Number(row.player_limit),
|
| 181 |
-
|
| 182 |
}));
|
| 183 |
return res.json({ plans });
|
| 184 |
} catch (error) { next(error); }
|
|
@@ -210,7 +210,7 @@ app.get("/api/plan-billing", async (req, res, next) => {
|
|
| 210 |
let subscription = null;
|
| 211 |
if (assignment?.subscription_id) {
|
| 212 |
const { data: plan, error } = await supabaseAdmin.from("subscriptions")
|
| 213 |
-
.select("subscription_id,plan,price,player_limit,
|
| 214 |
if (error) throw new Error(`Unable to load plan: ${error.message}`);
|
| 215 |
if (plan) {
|
| 216 |
const today = new Date().toISOString().slice(0, 10);
|
|
@@ -219,7 +219,7 @@ app.get("/api/plan-billing", async (req, res, next) => {
|
|
| 219 |
name: plan.plan,
|
| 220 |
price: Number(plan.price),
|
| 221 |
playerLimit: plan.player_limit == null ? null : Number(plan.player_limit),
|
| 222 |
-
|
| 223 |
startDate: assignment.startdate,
|
| 224 |
endDate: assignment.enddate,
|
| 225 |
status: today < assignment.startdate ? "scheduled" : today > assignment.enddate ? "expired" : "active",
|
|
|
|
| 139 |
return null;
|
| 140 |
}
|
| 141 |
if (await userIsAdmin(current.user.id)) {
|
| 142 |
+
return { ...current, isAdmin: true, subscription: { player_limit: null, session_limit: null } };
|
| 143 |
}
|
| 144 |
const subscription = await activeSubscriptionFor(current.user.id, { refresh: true });
|
| 145 |
if (!subscription) {
|
|
|
|
| 169 |
app.get("/api/subscriptions", async (_req, res, next) => {
|
| 170 |
try {
|
| 171 |
const { data, error } = await supabaseAdmin.from("subscriptions")
|
| 172 |
+
.select("subscription_id,plan,price,player_limit,session_limit")
|
| 173 |
.order("price", { ascending: true });
|
| 174 |
if (error) throw new Error(`Unable to load subscription plans: ${error.message}`);
|
| 175 |
const plans = (data ?? []).map((row) => ({
|
|
|
|
| 178 |
name: row.plan,
|
| 179 |
monthlyPrice: Number(row.price),
|
| 180 |
playerLimit: row.player_limit == null ? null : Number(row.player_limit),
|
| 181 |
+
sessionLimit: row.session_limit == null ? null : Number(row.session_limit),
|
| 182 |
}));
|
| 183 |
return res.json({ plans });
|
| 184 |
} catch (error) { next(error); }
|
|
|
|
| 210 |
let subscription = null;
|
| 211 |
if (assignment?.subscription_id) {
|
| 212 |
const { data: plan, error } = await supabaseAdmin.from("subscriptions")
|
| 213 |
+
.select("subscription_id,plan,price,player_limit,session_limit").eq("subscription_id", assignment.subscription_id).maybeSingle();
|
| 214 |
if (error) throw new Error(`Unable to load plan: ${error.message}`);
|
| 215 |
if (plan) {
|
| 216 |
const today = new Date().toISOString().slice(0, 10);
|
|
|
|
| 219 |
name: plan.plan,
|
| 220 |
price: Number(plan.price),
|
| 221 |
playerLimit: plan.player_limit == null ? null : Number(plan.player_limit),
|
| 222 |
+
sessionLimit: plan.session_limit == null ? null : Number(plan.session_limit),
|
| 223 |
startDate: assignment.startdate,
|
| 224 |
endDate: assignment.enddate,
|
| 225 |
status: today < assignment.startdate ? "scheduled" : today > assignment.enddate ? "expired" : "active",
|
src/subscriptions.ts
CHANGED
|
@@ -45,7 +45,7 @@ async function loadActiveSubscription(userId: string) {
|
|
| 45 |
if (!assignment?.subscription_id || assignment.startdate > today || assignment.enddate < today) return null;
|
| 46 |
|
| 47 |
const { data: plan, error: planError } = await supabaseAdmin.from("subscriptions")
|
| 48 |
-
.select("subscription_id,plan,price,player_limit,
|
| 49 |
if (planError) throw new Error(`Unable to load subscription plan: ${planError.message}`);
|
| 50 |
return plan ? { ...plan, startdate: assignment.startdate, enddate: assignment.enddate } : null;
|
| 51 |
}
|
|
|
|
| 45 |
if (!assignment?.subscription_id || assignment.startdate > today || assignment.enddate < today) return null;
|
| 46 |
|
| 47 |
const { data: plan, error: planError } = await supabaseAdmin.from("subscriptions")
|
| 48 |
+
.select("subscription_id,plan,price,player_limit,session_limit").eq("subscription_id", assignment.subscription_id).maybeSingle();
|
| 49 |
if (planError) throw new Error(`Unable to load subscription plan: ${planError.message}`);
|
| 50 |
return plan ? { ...plan, startdate: assignment.startdate, enddate: assignment.enddate } : null;
|
| 51 |
}
|