Spaces:
Running
Running
feat: improve profile synchronization to prevent usage counter resets
Browse files- auth/routes.py +19 -7
auth/routes.py
CHANGED
|
@@ -55,15 +55,24 @@ async def get_profile(
|
|
| 55 |
data["display_name"] = real_name
|
| 56 |
|
| 57 |
try:
|
| 58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
if res_upd.data:
|
| 60 |
user = _map_profile(res_upd.data[0])
|
| 61 |
except Exception:
|
| 62 |
-
#
|
| 63 |
try:
|
|
|
|
|
|
|
| 64 |
res_upd = (
|
| 65 |
_table_supabase("profiles")
|
| 66 |
-
.update(
|
| 67 |
.eq("id", user_id)
|
| 68 |
.execute()
|
| 69 |
)
|
|
@@ -75,19 +84,22 @@ async def get_profile(
|
|
| 75 |
pass
|
| 76 |
|
| 77 |
if not user:
|
| 78 |
-
# Last resort: synthetic profile from the JWT claims so the UI doesn't break
|
|
|
|
| 79 |
user_obj = current_user
|
| 80 |
uid = getattr(user_obj, "id", None) or (user_obj.get("id") if isinstance(user_obj, dict) else None)
|
| 81 |
if uid:
|
| 82 |
-
from src.store import _map_profile
|
| 83 |
meta = getattr(user_obj, "user_metadata", {}) or {}
|
|
|
|
|
|
|
| 84 |
user = _map_profile({
|
| 85 |
"id": uid,
|
| 86 |
"display_name": meta.get("full_name") or meta.get("name") or "User",
|
| 87 |
"email": getattr(user_obj, "email", "") or "",
|
| 88 |
"avatar_url": "",
|
| 89 |
-
"daily_requests": 0,
|
| 90 |
-
"last_request_date":
|
| 91 |
"_is_fallback": True,
|
| 92 |
})
|
| 93 |
|
|
|
|
| 55 |
data["display_name"] = real_name
|
| 56 |
|
| 57 |
try:
|
| 58 |
+
# Use upsert so we NEVER overwrite daily_requests / last_request_date
|
| 59 |
+
# on subsequent sign-ins. Only id/email/display_name are safe to set.
|
| 60 |
+
client = supabase # already resolved above
|
| 61 |
+
res_upd = (
|
| 62 |
+
client.table("profiles")
|
| 63 |
+
.upsert(data, on_conflict="id", ignore_duplicates=False)
|
| 64 |
+
.execute()
|
| 65 |
+
)
|
| 66 |
if res_upd.data:
|
| 67 |
user = _map_profile(res_upd.data[0])
|
| 68 |
except Exception:
|
| 69 |
+
# Upsert failed — fall back to a plain update (never resets usage)
|
| 70 |
try:
|
| 71 |
+
# Strip the id from the update payload to avoid PK conflicts
|
| 72 |
+
update_data = {k: v for k, v in data.items() if k != "id"}
|
| 73 |
res_upd = (
|
| 74 |
_table_supabase("profiles")
|
| 75 |
+
.update(update_data)
|
| 76 |
.eq("id", user_id)
|
| 77 |
.execute()
|
| 78 |
)
|
|
|
|
| 84 |
pass
|
| 85 |
|
| 86 |
if not user:
|
| 87 |
+
# Last resort: synthetic profile from the JWT claims so the UI doesn't break.
|
| 88 |
+
# We still try to fetch real usage from the DB to avoid resetting the counter.
|
| 89 |
user_obj = current_user
|
| 90 |
uid = getattr(user_obj, "id", None) or (user_obj.get("id") if isinstance(user_obj, dict) else None)
|
| 91 |
if uid:
|
| 92 |
+
from src.store import _map_profile, get_usage
|
| 93 |
meta = getattr(user_obj, "user_metadata", {}) or {}
|
| 94 |
+
# Fetch real usage so the fallback profile doesn't reset the counter to 0
|
| 95 |
+
real_usage = get_usage(uid)
|
| 96 |
user = _map_profile({
|
| 97 |
"id": uid,
|
| 98 |
"display_name": meta.get("full_name") or meta.get("name") or "User",
|
| 99 |
"email": getattr(user_obj, "email", "") or "",
|
| 100 |
"avatar_url": "",
|
| 101 |
+
"daily_requests": real_usage.get("used", 0),
|
| 102 |
+
"last_request_date": __import__('datetime').date.today().isoformat(),
|
| 103 |
"_is_fallback": True,
|
| 104 |
})
|
| 105 |
|