sare26 commited on
Commit
f22dba4
·
verified ·
1 Parent(s): 1be81b9

Update artifacts/api-server/src/routes/me/index.ts

Browse files
artifacts/api-server/src/routes/me/index.ts CHANGED
@@ -1,55 +1,66 @@
1
  import { Router, type Request, type Response } from "express";
2
  import { db, subscriptionsTable, usersTable } from "@workspace/db";
3
  import { eq } from "drizzle-orm";
4
- import { createClient } from "@supabase/supabase-js";
5
 
6
  const router = Router();
7
 
8
- const supabase = createClient(
9
- process.env.SUPABASE_URL || "",
10
- process.env.SUPABASE_SERVICE_ROLE_KEY || ""
11
- );
12
-
13
  function buildTrialEnd(): Date {
14
  return new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
15
  }
16
 
17
- router.get("/", async (req: Request, res: Response) => {
18
- const now = new Date();
19
- const authHeader = req.headers.authorization;
20
-
21
- let userId: string | null = null;
22
- let userEmail: string | null = null;
23
-
24
- if (authHeader?.startsWith("Bearer ")) {
25
- const token = authHeader.split(" ")[1];
26
- try {
27
- const { data: { user }, error } = await supabase.auth.getUser(token);
28
- if (!error && user) {
29
- userId = user.id;
30
- userEmail = user.email ?? null;
31
- }
32
- } catch {}
33
  }
 
 
34
 
35
- if (!userId) {
36
- userId = (req.query.userId as string) || null;
37
- userEmail = (req.query.userEmail as string) || null;
38
- }
39
 
40
- if (!userId) {
41
- return res.status(401).json({ error: "Unauthorized" });
42
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
- if (userEmail?.toLowerCase() === "saresare2555@hotmail.com") {
45
  return res.json({
46
- userId, email: userEmail,
47
- subscription: { status: "active", trialEnd: null, currentPeriodEnd: null, paypalSubscriptionId: null, hasAccess: true },
 
 
 
 
 
 
 
48
  });
49
  }
50
 
51
  try {
52
- // ========== 🆕 البحث عن مستخدم قديم بنفس البريد ==========
53
  if (userEmail) {
54
  const [legacyUser] = await db
55
  .select({
@@ -63,40 +74,37 @@ router.get("/", async (req: Request, res: Response) => {
63
  if (legacyUser) {
64
  console.log(`🔗 ربط: ${userEmail} | القديم=${legacyUser.id} | الجديد=${userId}`);
65
 
66
- // جلب اشتراك المستخدم القديم
67
  const [existingSub] = await db
68
  .select()
69
  .from(subscriptionsTable)
70
  .where(eq(subscriptionsTable.userId, legacyUser.id));
71
 
72
  if (existingSub) {
73
- // إذا كان userId مختلف، نحذف الاشتراك الجديد أولاً ثم ننقل القديم
74
  if (legacyUser.id !== userId) {
75
- // حذف الاشتراك الجديد (التجريبي الذي أنشئ عند أول دخول)
76
  await db
77
  .delete(subscriptionsTable)
78
  .where(eq(subscriptionsTable.userId, userId));
79
 
80
- // نقل الاشتراك القديم للمستخدم الجديد
81
  await db
82
  .update(subscriptionsTable)
83
  .set({ userId })
84
  .where(eq(subscriptionsTable.userId, legacyUser.id));
85
  }
86
 
87
- // تحديث بيانات المستخدم
88
  await db
89
  .insert(usersTable)
90
  .values({
91
  id: userId,
92
  email: userEmail.toLowerCase(),
93
- isBanned: false,
94
- lastSeenAt: now
 
95
  })
96
  .onConflictDoUpdate({
97
  target: usersTable.id,
98
  set: {
99
  email: userEmail.toLowerCase(),
 
100
  lastSeenAt: now,
101
  },
102
  });
@@ -104,23 +112,27 @@ router.get("/", async (req: Request, res: Response) => {
104
  let status: string = existingSub?.status ?? "none";
105
  let hasAccess = false;
106
 
107
- if (status === "trialing") {
108
- hasAccess = existingSub.trialEnd ? existingSub.trialEnd > now : false;
109
- if (!hasAccess) status = "trial_expired";
110
- } else if (status === "trial_expired" || status === "expired") {
111
- hasAccess = false;
112
- } else if (status === "active") {
113
- hasAccess = !existingSub.currentPeriodEnd || existingSub.currentPeriodEnd > now;
 
 
114
  }
115
 
 
116
  return res.json({
117
- userId, email: userEmail,
 
118
  subscription: {
119
  status,
120
  trialEnd: existingSub?.trialEnd?.toISOString() ?? null,
121
  currentPeriodEnd: existingSub?.currentPeriodEnd?.toISOString() ?? null,
122
- paypalSubscriptionId: null,
123
- hasAccess
124
  },
125
  isReturningUser: true,
126
  });
@@ -128,53 +140,102 @@ router.get("/", async (req: Request, res: Response) => {
128
  }
129
  }
130
 
131
- // ========== مستخدم جديد (لا يوجد له حساب قديم) ==========
132
- await db.insert(usersTable).values({
133
- id: userId,
134
- email: userEmail?.toLowerCase() ?? null,
135
- isBanned: false,
136
- lastSeenAt: now
137
- }).onConflictDoUpdate({
138
- target: usersTable.id,
139
- set: { email: userEmail?.toLowerCase() ?? null, lastSeenAt: now }
140
- });
141
-
142
- let [sub] = await db.select().from(subscriptionsTable).where(eq(subscriptionsTable.userId, userId));
 
 
 
 
 
 
 
 
 
 
 
143
 
144
  if (!sub) {
 
145
  const trialEnd = buildTrialEnd();
146
- const [created] = await db.insert(subscriptionsTable)
 
147
  .values({ userId, status: "trialing", trialEnd, updatedAt: now })
148
  .returning();
149
  sub = created;
150
  }
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  let status: string = sub?.status ?? "none";
153
  let hasAccess = false;
154
 
155
- if (status === "trialing") {
156
- hasAccess = sub?.trialEnd ? new Date(sub.trialEnd) > now : false;
157
- if (!hasAccess) status = "trial_expired";
158
- } else if (status === "active") {
159
- hasAccess = !sub?.currentPeriodEnd || new Date(sub.currentPeriodEnd) > now;
 
 
 
 
 
 
 
 
 
 
 
160
  }
161
 
 
162
  return res.json({
163
- userId, email: userEmail,
 
164
  subscription: {
165
  status,
166
  trialEnd: sub?.trialEnd?.toISOString() ?? null,
167
  currentPeriodEnd: sub?.currentPeriodEnd?.toISOString() ?? null,
168
- paypalSubscriptionId: null,
169
- hasAccess
170
  },
171
  isReturningUser: false,
172
  });
 
173
  } catch (error) {
174
- console.error("[me] خطأ:", error);
 
175
  return res.json({
176
- userId, email: userEmail,
177
- subscription: { status: "trialing", trialEnd: buildTrialEnd().toISOString(), currentPeriodEnd: null, paypalSubscriptionId: null, hasAccess: true }
 
 
 
 
 
 
 
178
  });
179
  }
180
  });
 
1
  import { Router, type Request, type Response } from "express";
2
  import { db, subscriptionsTable, usersTable } from "@workspace/db";
3
  import { eq } from "drizzle-orm";
4
+ import { requireAuth, type AuthedRequest } from "../../lib/auth";
5
 
6
  const router = Router();
7
 
 
 
 
 
 
8
  function buildTrialEnd(): Date {
9
  return new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
10
  }
11
 
12
+ function getClientIp(req: Request): string | null {
13
+ const forwarded = req.headers["x-forwarded-for"];
14
+ if (forwarded) {
15
+ const ip = Array.isArray(forwarded) ? forwarded[0] : forwarded.split(",")[0];
16
+ return ip?.trim() ?? null;
 
 
 
 
 
 
 
 
 
 
 
17
  }
18
+ return req.socket?.remoteAddress ?? null;
19
+ }
20
 
21
+ router.get("/", requireAuth, async (req: Request, res: Response) => {
22
+ const { userId, userEmail } = req as AuthedRequest;
23
+ const clientIp = getClientIp(req);
24
+ const now = new Date();
25
 
26
+ // 👑 استثناء حساب المالك الماستر
27
+ if (userEmail && userEmail.toLowerCase() === "saresare2555@hotmail.com") {
28
+ const [ownerSub] = await db
29
+ .select()
30
+ .from(subscriptionsTable)
31
+ .where(eq(subscriptionsTable.userId, userId));
32
+
33
+ if (ownerSub && ownerSub.status === "trial_expired") {
34
+ res.set("Cache-Control", "private, max-age=60");
35
+ return res.json({
36
+ userId,
37
+ email: userEmail,
38
+ subscription: {
39
+ status: "trial_expired",
40
+ trialEnd: ownerSub.trialEnd?.toISOString() ?? null,
41
+ currentPeriodEnd: null,
42
+ paypalSubscriptionId: null,
43
+ hasAccess: false,
44
+ },
45
+ });
46
+ }
47
 
48
+ res.set("Cache-Control", "private, max-age=60");
49
  return res.json({
50
+ userId,
51
+ email: userEmail,
52
+ subscription: {
53
+ status: "active",
54
+ trialEnd: null,
55
+ currentPeriodEnd: null,
56
+ paypalSubscriptionId: null,
57
+ hasAccess: true,
58
+ },
59
  });
60
  }
61
 
62
  try {
63
+ // ========== البحث عن مستخدم قديم بنفس البريد ==========
64
  if (userEmail) {
65
  const [legacyUser] = await db
66
  .select({
 
74
  if (legacyUser) {
75
  console.log(`🔗 ربط: ${userEmail} | القديم=${legacyUser.id} | الجديد=${userId}`);
76
 
 
77
  const [existingSub] = await db
78
  .select()
79
  .from(subscriptionsTable)
80
  .where(eq(subscriptionsTable.userId, legacyUser.id));
81
 
82
  if (existingSub) {
 
83
  if (legacyUser.id !== userId) {
 
84
  await db
85
  .delete(subscriptionsTable)
86
  .where(eq(subscriptionsTable.userId, userId));
87
 
 
88
  await db
89
  .update(subscriptionsTable)
90
  .set({ userId })
91
  .where(eq(subscriptionsTable.userId, legacyUser.id));
92
  }
93
 
 
94
  await db
95
  .insert(usersTable)
96
  .values({
97
  id: userId,
98
  email: userEmail.toLowerCase(),
99
+ ipAddress: clientIp,
100
+ lastSeenAt: now,
101
+ isBanned: false
102
  })
103
  .onConflictDoUpdate({
104
  target: usersTable.id,
105
  set: {
106
  email: userEmail.toLowerCase(),
107
+ ipAddress: clientIp,
108
  lastSeenAt: now,
109
  },
110
  });
 
112
  let status: string = existingSub?.status ?? "none";
113
  let hasAccess = false;
114
 
115
+ if (existingSub) {
116
+ if (status === "trialing") {
117
+ hasAccess = existingSub.trialEnd ? existingSub.trialEnd > now : false;
118
+ if (!hasAccess) status = "trial_expired";
119
+ } else if (status === "trial_expired" || status === "expired") {
120
+ hasAccess = false;
121
+ } else if (status === "active") {
122
+ hasAccess = !existingSub.currentPeriodEnd || existingSub.currentPeriodEnd > now;
123
+ }
124
  }
125
 
126
+ res.set("Cache-Control", "private, max-age=60");
127
  return res.json({
128
+ userId,
129
+ email: userEmail,
130
  subscription: {
131
  status,
132
  trialEnd: existingSub?.trialEnd?.toISOString() ?? null,
133
  currentPeriodEnd: existingSub?.currentPeriodEnd?.toISOString() ?? null,
134
+ paypalSubscriptionId: existingSub?.paypalSubscriptionId ?? null,
135
+ hasAccess,
136
  },
137
  isReturningUser: true,
138
  });
 
140
  }
141
  }
142
 
143
+ // ========== مستخدم جديد ==========
144
+ await db
145
+ .insert(usersTable)
146
+ .values({
147
+ id: userId,
148
+ email: userEmail ? userEmail.toLowerCase() : null,
149
+ ipAddress: clientIp,
150
+ lastSeenAt: now,
151
+ isBanned: false
152
+ })
153
+ .onConflictDoUpdate({
154
+ target: usersTable.id,
155
+ set: {
156
+ email: userEmail ? userEmail.toLowerCase() : null,
157
+ ipAddress: clientIp,
158
+ lastSeenAt: now,
159
+ },
160
+ });
161
+
162
+ let [sub] = await db
163
+ .select()
164
+ .from(subscriptionsTable)
165
+ .where(eq(subscriptionsTable.userId, userId));
166
 
167
  if (!sub) {
168
+ console.log(`[me] إنشاء اشتراك تجريبي جديد لـ userId=${userId}`);
169
  const trialEnd = buildTrialEnd();
170
+ const [created] = await db
171
+ .insert(subscriptionsTable)
172
  .values({ userId, status: "trialing", trialEnd, updatedAt: now })
173
  .returning();
174
  sub = created;
175
  }
176
 
177
+ [sub] = await db
178
+ .select()
179
+ .from(subscriptionsTable)
180
+ .where(eq(subscriptionsTable.userId, userId));
181
+
182
+ const [userCheck] = await db
183
+ .select({ isBanned: usersTable.isBanned })
184
+ .from(usersTable)
185
+ .where(eq(usersTable.id, userId));
186
+
187
+ if (userCheck?.isBanned) {
188
+ return res.status(403).json({ error: "banned", message: "تم إيقاف هذا الحساب." });
189
+ }
190
+
191
  let status: string = sub?.status ?? "none";
192
  let hasAccess = false;
193
 
194
+ if (sub) {
195
+ if (status === "trialing") {
196
+ if (sub.trialEnd && sub.trialEnd > now) {
197
+ hasAccess = true;
198
+ } else if (sub.trialEnd && sub.trialEnd <= now) {
199
+ status = "trial_expired";
200
+ }
201
+ }
202
+ else if (status === "trial_expired" || status === "expired") {
203
+ hasAccess = false;
204
+ }
205
+ else if (status === "active") {
206
+ if (!sub.currentPeriodEnd || sub.currentPeriodEnd > now) {
207
+ hasAccess = true;
208
+ }
209
+ }
210
  }
211
 
212
+ res.set("Cache-Control", "private, max-age=60");
213
  return res.json({
214
+ userId,
215
+ email: userEmail,
216
  subscription: {
217
  status,
218
  trialEnd: sub?.trialEnd?.toISOString() ?? null,
219
  currentPeriodEnd: sub?.currentPeriodEnd?.toISOString() ?? null,
220
+ paypalSubscriptionId: sub?.paypalSubscriptionId ?? null,
221
+ hasAccess,
222
  },
223
  isReturningUser: false,
224
  });
225
+
226
  } catch (error) {
227
+ console.error("[me] خطأ في جلب/إنشاء المستخدم:", error);
228
+ res.set("Cache-Control", "private, max-age=60");
229
  return res.json({
230
+ userId,
231
+ email: userEmail,
232
+ subscription: {
233
+ status: "trialing",
234
+ trialEnd: buildTrialEnd().toISOString(),
235
+ currentPeriodEnd: null,
236
+ paypalSubscriptionId: null,
237
+ hasAccess: true,
238
+ },
239
  });
240
  }
241
  });