Shoraky commited on
Commit
e2ead0c
·
1 Parent(s): d1ceac4

Use plan-period session usage counter

Browse files
Files changed (3) hide show
  1. src/admin.ts +6 -6
  2. src/analysis.ts +2 -2
  3. src/server.ts +3 -4
src/admin.ts CHANGED
@@ -64,7 +64,7 @@ export function registerAdminRoutes(app: Express) {
64
  if (error) throw new Error(`Unable to load user directory: ${error.message}`);
65
  const ids = (data ?? []).map((row) => row.user_id);
66
  const [subs, counts] = ids.length ? await Promise.all([
67
- supabaseAdmin.from("users_subscriptions").select("user_id,subscription_id,startdate,enddate,num_players,num_sessions,num_sessions_month").in("user_id", ids),
68
  supabaseAdmin.from("sessions").select("user_id").in("user_id", ids),
69
  ]) : [{ data: [], error: null }, { data: [], error: null }];
70
  if (subs.error) throw new Error(`Unable to load user plans: ${subs.error.message}`);
@@ -85,7 +85,7 @@ export function registerAdminRoutes(app: Express) {
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.monthly_session_limit } : null,
88
- usage: { players: assignment?.num_players ?? 0, sessions: assignment?.num_sessions_month ?? assignment?.num_sessions ?? 0, totalSessions: sessionCounts.get(row.user_id) ?? 0 },
89
  };
90
  }) });
91
  }));
@@ -102,7 +102,7 @@ export function registerAdminRoutes(app: Express) {
102
  const id = uuid.safeParse(req.params.userId); if (!id.success) return res.sendStatus(404);
103
  const [{ data: user, error }, { data: assignment, error: subError }] = await Promise.all([
104
  supabaseAdmin.from("users").select("user_id,fname,lname,email,academy,role,image_path,account_role").eq("user_id", id.data).maybeSingle(),
105
- supabaseAdmin.from("users_subscriptions").select("subscription_id,startdate,enddate,num_players,num_sessions,num_sessions_month").eq("user_id", id.data).maybeSingle(),
106
  ]);
107
  if (error) throw new Error(`Unable to load user: ${error.message}`);
108
  if (subError) throw new Error(`Unable to load user plan: ${subError.message}`);
@@ -135,8 +135,8 @@ export function registerAdminRoutes(app: Express) {
135
  if (!plan) return fail(res, 404, "Plan not found.");
136
  const { data: row, error } = await supabaseAdmin.from("users_subscriptions").upsert({
137
  user_id: id.data, subscription_id: plan.subscription_id, startdate: input.data.startDate, enddate: input.data.endDate,
138
- num_players: 0, num_sessions: 0, num_sessions_month: 0,
139
- }, { onConflict: "user_id" }).select("user_id,subscription_id,startdate,enddate,num_players,num_sessions,num_sessions_month").single();
140
  if (error) throw new Error(`Unable to assign plan: ${error.message}`);
141
  invalidateSubscriptionCache(id.data);
142
  return res.json({ subscription: row });
@@ -145,7 +145,7 @@ export function registerAdminRoutes(app: Express) {
145
  app.delete("/api/admin/users/:userId/subscription", asyncRoute(async (req, res) => {
146
  if (!await admin(req, res)) return;
147
  const id = uuid.safeParse(req.params.userId); if (!id.success) return res.sendStatus(404);
148
- const { error } = await supabaseAdmin.from("users_subscriptions").update({ subscription_id: null, num_players: 0, num_sessions: 0, num_sessions_month: 0 })
149
  .eq("user_id", id.data);
150
  if (error) throw new Error(`Unable to cancel plan: ${error.message}`);
151
  invalidateSubscriptionCache(id.data);
 
64
  if (error) throw new Error(`Unable to load user directory: ${error.message}`);
65
  const ids = (data ?? []).map((row) => row.user_id);
66
  const [subs, counts] = ids.length ? await Promise.all([
67
+ supabaseAdmin.from("users_subscriptions").select("user_id,subscription_id,startdate,enddate,num_players,num_sessions").in("user_id", ids),
68
  supabaseAdmin.from("sessions").select("user_id").in("user_id", ids),
69
  ]) : [{ data: [], error: null }, { data: [], error: null }];
70
  if (subs.error) throw new Error(`Unable to load user plans: ${subs.error.message}`);
 
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.monthly_session_limit } : null,
88
+ usage: { players: assignment?.num_players ?? 0, sessions: assignment?.num_sessions ?? 0, totalSessions: sessionCounts.get(row.user_id) ?? 0 },
89
  };
90
  }) });
91
  }));
 
102
  const id = uuid.safeParse(req.params.userId); if (!id.success) return res.sendStatus(404);
103
  const [{ data: user, error }, { data: assignment, error: subError }] = await Promise.all([
104
  supabaseAdmin.from("users").select("user_id,fname,lname,email,academy,role,image_path,account_role").eq("user_id", id.data).maybeSingle(),
105
+ supabaseAdmin.from("users_subscriptions").select("subscription_id,startdate,enddate,num_players,num_sessions").eq("user_id", id.data).maybeSingle(),
106
  ]);
107
  if (error) throw new Error(`Unable to load user: ${error.message}`);
108
  if (subError) throw new Error(`Unable to load user plan: ${subError.message}`);
 
135
  if (!plan) return fail(res, 404, "Plan not found.");
136
  const { data: row, error } = await supabaseAdmin.from("users_subscriptions").upsert({
137
  user_id: id.data, subscription_id: plan.subscription_id, startdate: input.data.startDate, enddate: input.data.endDate,
138
+ num_players: 0, num_sessions: 0,
139
+ }, { onConflict: "user_id" }).select("user_id,subscription_id,startdate,enddate,num_players,num_sessions").single();
140
  if (error) throw new Error(`Unable to assign plan: ${error.message}`);
141
  invalidateSubscriptionCache(id.data);
142
  return res.json({ subscription: row });
 
145
  app.delete("/api/admin/users/:userId/subscription", asyncRoute(async (req, res) => {
146
  if (!await admin(req, res)) return;
147
  const id = uuid.safeParse(req.params.userId); if (!id.success) return res.sendStatus(404);
148
+ const { error } = await supabaseAdmin.from("users_subscriptions").update({ subscription_id: null, num_players: 0, num_sessions: 0 })
149
  .eq("user_id", id.data);
150
  if (error) throw new Error(`Unable to cancel plan: ${error.message}`);
151
  invalidateSubscriptionCache(id.data);
src/analysis.ts CHANGED
@@ -54,9 +54,9 @@ export function analysisRouter(db: SupabaseClient, secret: string) {
54
  }
55
  if (!isAdmin) {
56
  const { data: usage, error: usageError } = await db.from("users_subscriptions")
57
- .select("num_sessions_month").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_month ?? 0);
60
  const sessionLimit = subscription?.monthly_session_limit == null ? null : Number(subscription.monthly_session_limit);
61
  if (sessionLimit !== null && usedSessions >= sessionLimit) {
62
  return res.status(403).json({
 
54
  }
55
  if (!isAdmin) {
56
  const { data: usage, error: usageError } = await db.from("users_subscriptions")
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?.monthly_session_limit == null ? null : Number(subscription.monthly_session_limit);
61
  if (sessionLimit !== null && usedSessions >= sessionLimit) {
62
  return res.status(403).json({
src/server.ts CHANGED
@@ -201,10 +201,10 @@ app.get("/api/plan-billing", async (req, res, next) => {
201
  const userId = current.user.id;
202
  if (await userIsAdmin(userId)) {
203
  res.set("Cache-Control", "no-store");
204
- return res.json({ subscription: null, usage: { players: 0, sessions: 0, monthlySessions: 0 }, billingHistoryAvailable: false, isAdmin: true });
205
  }
206
  const assignmentResult = await supabaseAdmin.from("users_subscriptions")
207
- .select("subscription_id,startdate,enddate,num_players,num_sessions,num_sessions_month").eq("user_id", userId).maybeSingle();
208
  if (assignmentResult.error) throw new Error(`Unable to load plan assignment: ${assignmentResult.error.message}`);
209
  const assignment = assignmentResult.data;
210
  let subscription = null;
@@ -227,8 +227,7 @@ app.get("/api/plan-billing", async (req, res, next) => {
227
  }
228
  }
229
  res.set("Cache-Control", "no-store");
230
- const monthlySessionUsage = Number(assignment?.num_sessions_month ?? 0);
231
- return res.json({ subscription, usage: { players: assignment?.num_players ?? 0, sessions: assignment?.num_sessions ?? 0, monthlySessions: monthlySessionUsage }, billingHistoryAvailable: false });
232
  } catch (error) { next(error); }
233
  });
234
 
 
201
  const userId = current.user.id;
202
  if (await userIsAdmin(userId)) {
203
  res.set("Cache-Control", "no-store");
204
+ return res.json({ subscription: null, usage: { players: 0, sessions: 0 }, billingHistoryAvailable: false, isAdmin: true });
205
  }
206
  const assignmentResult = await supabaseAdmin.from("users_subscriptions")
207
+ .select("subscription_id,startdate,enddate,num_players,num_sessions").eq("user_id", userId).maybeSingle();
208
  if (assignmentResult.error) throw new Error(`Unable to load plan assignment: ${assignmentResult.error.message}`);
209
  const assignment = assignmentResult.data;
210
  let subscription = null;
 
227
  }
228
  }
229
  res.set("Cache-Control", "no-store");
230
+ return res.json({ subscription, usage: { players: assignment?.num_players ?? 0, sessions: Number(assignment?.num_sessions ?? 0) }, billingHistoryAvailable: false });
 
231
  } catch (error) { next(error); }
232
  });
233