新增积分转账功能:支持管理员手动扣除和划转用户积分
This commit is contained in:
@@ -1258,6 +1258,80 @@ class DBManager:
|
||||
"points_after": after,
|
||||
}
|
||||
|
||||
def deduct_points_by_supabase_email(
|
||||
self,
|
||||
supabase_email: str,
|
||||
amount: int,
|
||||
) -> Dict[str, Any]:
|
||||
email = str(supabase_email or "").strip().lower()
|
||||
points = int(amount or 0)
|
||||
if not email:
|
||||
return {"ok": False, "reason": "invalid_supabase_email"}
|
||||
if points <= 0:
|
||||
return {"ok": False, "reason": "invalid_amount"}
|
||||
|
||||
with self._get_connection() as conn:
|
||||
conn.row_factory = sqlite3.Row
|
||||
row = conn.execute(
|
||||
"""
|
||||
SELECT telegram_id, username, points, supabase_email
|
||||
FROM users
|
||||
WHERE lower(trim(COALESCE(supabase_email, ''))) = ?
|
||||
LIMIT 1
|
||||
""",
|
||||
(email,),
|
||||
).fetchone()
|
||||
if not row:
|
||||
return {"ok": False, "reason": "user_not_found", "supabase_email": email}
|
||||
|
||||
telegram_id = int(row["telegram_id"] or 0)
|
||||
before = int(row["points"] or 0)
|
||||
if before < points:
|
||||
return {
|
||||
"ok": False,
|
||||
"reason": "insufficient_points",
|
||||
"points_available": before,
|
||||
"points_needed": points,
|
||||
}
|
||||
after = before - points
|
||||
conn.execute(
|
||||
"UPDATE users SET points = ? WHERE telegram_id = ?",
|
||||
(after, telegram_id),
|
||||
)
|
||||
conn.commit()
|
||||
self._sync_points_to_supabase_user_metadata(telegram_id)
|
||||
return {
|
||||
"ok": True,
|
||||
"telegram_id": telegram_id,
|
||||
"username": str(row["username"] or ""),
|
||||
"supabase_email": str(row["supabase_email"] or email),
|
||||
"points_before": before,
|
||||
"points_deducted": points,
|
||||
"points_after": after,
|
||||
}
|
||||
|
||||
def transfer_points_by_email(
|
||||
self,
|
||||
from_email: str,
|
||||
to_email: str,
|
||||
amount: int,
|
||||
) -> Dict[str, Any]:
|
||||
"""Transfer points from one user to another within a single transaction."""
|
||||
r_from = self.deduct_points_by_supabase_email(from_email, amount)
|
||||
if not r_from.get("ok"):
|
||||
return {"ok": False, "reason": f"deduct_failed: {r_from.get('reason')}", "from": r_from}
|
||||
r_to = self.grant_points_by_supabase_email(to_email, amount)
|
||||
if not r_to.get("ok"):
|
||||
# Rollback: grant back to source
|
||||
self.grant_points_by_supabase_email(from_email, amount)
|
||||
return {"ok": False, "reason": f"grant_failed: {r_to.get('reason')}", "to": r_to}
|
||||
return {
|
||||
"ok": True,
|
||||
"from": r_from,
|
||||
"to": r_to,
|
||||
"amount": amount,
|
||||
}
|
||||
|
||||
def upsert_user(self, telegram_id: int, username: str):
|
||||
with self._get_connection() as conn:
|
||||
conn.execute("""
|
||||
|
||||
Reference in New Issue
Block a user