Spaces:
Sleeping
Sleeping
table optimise
Browse files- core/models.py +25 -21
- routers/auth.py +7 -9
- routers/blink.py +4 -6
- routers/contact.py +1 -1
- routers/gemini.py +7 -7
- routers/payments.py +5 -5
- services/credit_service.py +1 -1
core/models.py
CHANGED
|
@@ -11,7 +11,7 @@ Tables:
|
|
| 11 |
- ApiKeyUsage: API key load balancing
|
| 12 |
- RateLimit: Rate limiting
|
| 13 |
"""
|
| 14 |
-
from sqlalchemy import Column, Integer, String, Text, DateTime, JSON, Boolean, ForeignKey
|
| 15 |
from sqlalchemy.orm import relationship
|
| 16 |
from sqlalchemy.sql import func
|
| 17 |
from core.database import Base
|
|
@@ -29,8 +29,8 @@ class User(Base):
|
|
| 29 |
"""
|
| 30 |
__tablename__ = "users"
|
| 31 |
|
| 32 |
-
id = Column(Integer, primary_key=True, autoincrement=True
|
| 33 |
-
user_id = Column(String(50), unique=True, index=True, nullable=False) # Backend generated UUID
|
| 34 |
email = Column(String(255), unique=True, index=True, nullable=False)
|
| 35 |
|
| 36 |
# Google OAuth fields
|
|
@@ -72,13 +72,12 @@ class ClientUser(Base):
|
|
| 72 |
"""
|
| 73 |
__tablename__ = "client_users"
|
| 74 |
|
| 75 |
-
id = Column(Integer, primary_key=True, autoincrement=True
|
| 76 |
-
user_id = Column(
|
| 77 |
client_user_id = Column(String(100), index=True, nullable=True) # Client-side temp identifier
|
| 78 |
|
| 79 |
-
# IP tracking for network/location correlation
|
| 80 |
-
|
| 81 |
-
ipv6_address = Column(String(45), nullable=True, index=True)
|
| 82 |
|
| 83 |
# Device identification
|
| 84 |
device_fingerprint = Column(String(255), nullable=True, index=True) # Browser fingerprint hash
|
|
@@ -110,11 +109,11 @@ class AuditLog(Base):
|
|
| 110 |
"""
|
| 111 |
__tablename__ = "audit_logs"
|
| 112 |
|
| 113 |
-
id = Column(Integer, primary_key=True, autoincrement=True
|
| 114 |
log_type = Column(String(20), index=True, nullable=False) # "client" or "server"
|
| 115 |
|
| 116 |
# User tracking
|
| 117 |
-
user_id = Column(
|
| 118 |
client_user_id = Column(String(100), nullable=True, index=True) # For anonymous client logs
|
| 119 |
|
| 120 |
# Event details
|
|
@@ -150,17 +149,22 @@ class GeminiJob(Base):
|
|
| 150 |
Uses priority-tier system for worker assignment.
|
| 151 |
"""
|
| 152 |
__tablename__ = "gemini_jobs"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
|
| 154 |
-
id = Column(Integer, primary_key=True, autoincrement=True
|
| 155 |
job_id = Column(String(100), unique=True, index=True, nullable=False) # Our ID for client
|
| 156 |
-
user_id = Column(
|
| 157 |
job_type = Column(String(20), index=True, nullable=False) # video, image, text, analyze
|
| 158 |
third_party_id = Column(String(255), nullable=True) # Gemini operation name (for video)
|
| 159 |
-
status = Column(String(20), default="queued"
|
| 160 |
|
| 161 |
-
# Priority-tier worker system
|
| 162 |
-
priority = Column(String(10), default="fast"
|
| 163 |
-
next_process_at = Column(DateTime(timezone=True), nullable=True
|
| 164 |
retry_count = Column(Integer, default=0) # Number of status check retries
|
| 165 |
|
| 166 |
input_data = Column(JSON, nullable=True) # Request details (prompt, settings, etc.)
|
|
@@ -193,9 +197,9 @@ class PaymentTransaction(Base):
|
|
| 193 |
"""
|
| 194 |
__tablename__ = "payment_transactions"
|
| 195 |
|
| 196 |
-
id = Column(Integer, primary_key=True, autoincrement=True
|
| 197 |
transaction_id = Column(String(50), unique=True, index=True, nullable=False) # Our internal ID
|
| 198 |
-
user_id = Column(
|
| 199 |
|
| 200 |
# Order details
|
| 201 |
gateway = Column(String(20), nullable=False) # razorpay, stripe
|
|
@@ -239,8 +243,8 @@ class Contact(Base):
|
|
| 239 |
"""
|
| 240 |
__tablename__ = "contacts"
|
| 241 |
|
| 242 |
-
id = Column(Integer, primary_key=True, autoincrement=True
|
| 243 |
-
user_id = Column(
|
| 244 |
email = Column(String(255), nullable=False, index=True) # User's email
|
| 245 |
subject = Column(String(500), nullable=True)
|
| 246 |
message = Column(Text, nullable=False)
|
|
@@ -260,7 +264,7 @@ class RateLimit(Base):
|
|
| 260 |
"""
|
| 261 |
__tablename__ = "rate_limits"
|
| 262 |
|
| 263 |
-
id = Column(Integer, primary_key=True, autoincrement=True
|
| 264 |
identifier = Column(String(255), index=True, nullable=False) # IP or email
|
| 265 |
endpoint = Column(String(255), index=True, nullable=False)
|
| 266 |
attempts = Column(Integer, default=0)
|
|
|
|
| 11 |
- ApiKeyUsage: API key load balancing
|
| 12 |
- RateLimit: Rate limiting
|
| 13 |
"""
|
| 14 |
+
from sqlalchemy import Column, Integer, String, Text, DateTime, JSON, Boolean, ForeignKey, Index
|
| 15 |
from sqlalchemy.orm import relationship
|
| 16 |
from sqlalchemy.sql import func
|
| 17 |
from core.database import Base
|
|
|
|
| 29 |
"""
|
| 30 |
__tablename__ = "users"
|
| 31 |
|
| 32 |
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
| 33 |
+
user_id = Column(String(50), unique=True, index=True, nullable=False) # Backend generated UUID (public-facing)
|
| 34 |
email = Column(String(255), unique=True, index=True, nullable=False)
|
| 35 |
|
| 36 |
# Google OAuth fields
|
|
|
|
| 72 |
"""
|
| 73 |
__tablename__ = "client_users"
|
| 74 |
|
| 75 |
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
| 76 |
+
user_id = Column(Integer, ForeignKey("users.id"), index=True, nullable=True) # FK to users.id (nullable for anonymous)
|
| 77 |
client_user_id = Column(String(100), index=True, nullable=True) # Client-side temp identifier
|
| 78 |
|
| 79 |
+
# IP tracking for network/location correlation (standardized to single column)
|
| 80 |
+
ip_address = Column(String(45), nullable=True, index=True) # Supports both IPv4 and IPv6
|
|
|
|
| 81 |
|
| 82 |
# Device identification
|
| 83 |
device_fingerprint = Column(String(255), nullable=True, index=True) # Browser fingerprint hash
|
|
|
|
| 109 |
"""
|
| 110 |
__tablename__ = "audit_logs"
|
| 111 |
|
| 112 |
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
| 113 |
log_type = Column(String(20), index=True, nullable=False) # "client" or "server"
|
| 114 |
|
| 115 |
# User tracking
|
| 116 |
+
user_id = Column(Integer, ForeignKey("users.id"), nullable=True, index=True) # FK to users.id
|
| 117 |
client_user_id = Column(String(100), nullable=True, index=True) # For anonymous client logs
|
| 118 |
|
| 119 |
# Event details
|
|
|
|
| 149 |
Uses priority-tier system for worker assignment.
|
| 150 |
"""
|
| 151 |
__tablename__ = "gemini_jobs"
|
| 152 |
+
|
| 153 |
+
# Composite index for efficient queue polling: WHERE status = X AND next_process_at <= NOW() ORDER BY priority
|
| 154 |
+
__table_args__ = (
|
| 155 |
+
Index('ix_jobs_queue_poll', 'status', 'next_process_at', 'priority'),
|
| 156 |
+
)
|
| 157 |
|
| 158 |
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
| 159 |
job_id = Column(String(100), unique=True, index=True, nullable=False) # Our ID for client
|
| 160 |
+
user_id = Column(Integer, ForeignKey("users.id"), index=True, nullable=False) # FK to users.id
|
| 161 |
job_type = Column(String(20), index=True, nullable=False) # video, image, text, analyze
|
| 162 |
third_party_id = Column(String(255), nullable=True) # Gemini operation name (for video)
|
| 163 |
+
status = Column(String(20), default="queued") # queued, processing, completed, failed, cancelled
|
| 164 |
|
| 165 |
+
# Priority-tier worker system (indexed via composite index above)
|
| 166 |
+
priority = Column(String(10), default="fast") # fast (5s), medium (30s), slow (60s)
|
| 167 |
+
next_process_at = Column(DateTime(timezone=True), nullable=True) # When worker should pick up again
|
| 168 |
retry_count = Column(Integer, default=0) # Number of status check retries
|
| 169 |
|
| 170 |
input_data = Column(JSON, nullable=True) # Request details (prompt, settings, etc.)
|
|
|
|
| 197 |
"""
|
| 198 |
__tablename__ = "payment_transactions"
|
| 199 |
|
| 200 |
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
| 201 |
transaction_id = Column(String(50), unique=True, index=True, nullable=False) # Our internal ID
|
| 202 |
+
user_id = Column(Integer, ForeignKey("users.id"), index=True, nullable=False) # FK to users.id
|
| 203 |
|
| 204 |
# Order details
|
| 205 |
gateway = Column(String(20), nullable=False) # razorpay, stripe
|
|
|
|
| 243 |
"""
|
| 244 |
__tablename__ = "contacts"
|
| 245 |
|
| 246 |
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
| 247 |
+
user_id = Column(Integer, ForeignKey("users.id"), index=True, nullable=False) # FK to users.id
|
| 248 |
email = Column(String(255), nullable=False, index=True) # User's email
|
| 249 |
subject = Column(String(500), nullable=True)
|
| 250 |
message = Column(Text, nullable=False)
|
|
|
|
| 264 |
"""
|
| 265 |
__tablename__ = "rate_limits"
|
| 266 |
|
| 267 |
+
id = Column(Integer, primary_key=True, autoincrement=True)
|
| 268 |
identifier = Column(String(255), index=True, nullable=False) # IP or email
|
| 269 |
endpoint = Column(String(255), index=True, nullable=False)
|
| 270 |
attempts = Column(Integer, default=0)
|
routers/auth.py
CHANGED
|
@@ -145,7 +145,7 @@ async def google_auth(
|
|
| 145 |
if request.temp_user_id:
|
| 146 |
# Check if this client mapping exists
|
| 147 |
client_query = select(ClientUser).where(
|
| 148 |
-
ClientUser.user_id == user.
|
| 149 |
ClientUser.client_user_id == request.temp_user_id
|
| 150 |
)
|
| 151 |
client_result = await db.execute(client_query)
|
|
@@ -154,10 +154,9 @@ async def google_auth(
|
|
| 154 |
if not existing_client:
|
| 155 |
# Create new client user mapping
|
| 156 |
client_user = ClientUser(
|
| 157 |
-
user_id=user.
|
| 158 |
client_user_id=request.temp_user_id,
|
| 159 |
-
|
| 160 |
-
ipv6_address=ip if ":" in ip else None,
|
| 161 |
last_seen_at=datetime.utcnow()
|
| 162 |
)
|
| 163 |
db.add(client_user)
|
|
@@ -181,10 +180,9 @@ async def google_auth(
|
|
| 181 |
# Create client user mapping if temp_user_id provided
|
| 182 |
if request.temp_user_id:
|
| 183 |
client_user = ClientUser(
|
| 184 |
-
user_id=user.
|
| 185 |
client_user_id=request.temp_user_id,
|
| 186 |
-
|
| 187 |
-
ipv6_address=ip if ":" in ip else None,
|
| 188 |
last_seen_at=datetime.utcnow()
|
| 189 |
)
|
| 190 |
db.add(client_user)
|
|
@@ -192,7 +190,7 @@ async def google_auth(
|
|
| 192 |
# Log successful auth
|
| 193 |
audit_log = AuditLog(
|
| 194 |
log_type="server",
|
| 195 |
-
user_id=user.
|
| 196 |
client_user_id=request.temp_user_id,
|
| 197 |
action="google_auth",
|
| 198 |
ip_address=ip,
|
|
@@ -332,7 +330,7 @@ async def logout(
|
|
| 332 |
# Log logout
|
| 333 |
audit_log = AuditLog(
|
| 334 |
log_type="server",
|
| 335 |
-
user_id=user.
|
| 336 |
action="logout",
|
| 337 |
ip_address=ip,
|
| 338 |
status="success"
|
|
|
|
| 145 |
if request.temp_user_id:
|
| 146 |
# Check if this client mapping exists
|
| 147 |
client_query = select(ClientUser).where(
|
| 148 |
+
ClientUser.user_id == user.id, # Integer FK comparison
|
| 149 |
ClientUser.client_user_id == request.temp_user_id
|
| 150 |
)
|
| 151 |
client_result = await db.execute(client_query)
|
|
|
|
| 154 |
if not existing_client:
|
| 155 |
# Create new client user mapping
|
| 156 |
client_user = ClientUser(
|
| 157 |
+
user_id=user.id, # Integer FK to users.id
|
| 158 |
client_user_id=request.temp_user_id,
|
| 159 |
+
ip_address=ip, # Standardized IP column
|
|
|
|
| 160 |
last_seen_at=datetime.utcnow()
|
| 161 |
)
|
| 162 |
db.add(client_user)
|
|
|
|
| 180 |
# Create client user mapping if temp_user_id provided
|
| 181 |
if request.temp_user_id:
|
| 182 |
client_user = ClientUser(
|
| 183 |
+
user_id=user.id, # Integer FK to users.id (will be set after flush)
|
| 184 |
client_user_id=request.temp_user_id,
|
| 185 |
+
ip_address=ip, # Standardized IP column
|
|
|
|
| 186 |
last_seen_at=datetime.utcnow()
|
| 187 |
)
|
| 188 |
db.add(client_user)
|
|
|
|
| 190 |
# Log successful auth
|
| 191 |
audit_log = AuditLog(
|
| 192 |
log_type="server",
|
| 193 |
+
user_id=user.id, # Integer FK to users.id
|
| 194 |
client_user_id=request.temp_user_id,
|
| 195 |
action="google_auth",
|
| 196 |
ip_address=ip,
|
|
|
|
| 330 |
# Log logout
|
| 331 |
audit_log = AuditLog(
|
| 332 |
log_type="server",
|
| 333 |
+
user_id=user.id, # Integer FK to users.id
|
| 334 |
action="logout",
|
| 335 |
ip_address=ip,
|
| 336 |
status="success"
|
routers/blink.py
CHANGED
|
@@ -177,8 +177,7 @@ async def get_client_users(
|
|
| 177 |
"id": item.id,
|
| 178 |
"user_id": item.user_id,
|
| 179 |
"client_user_id": item.client_user_id,
|
| 180 |
-
"
|
| 181 |
-
"ipv6_address": item.ipv6_address,
|
| 182 |
"device_fingerprint": item.device_fingerprint,
|
| 183 |
"device_info": item.device_info,
|
| 184 |
"created_at": item.created_at.isoformat() if item.created_at else None,
|
|
@@ -495,14 +494,13 @@ async def blink(
|
|
| 495 |
country, region = await get_geolocation(ip_address)
|
| 496 |
|
| 497 |
# Determine server user_id (if authenticated)
|
| 498 |
-
server_user_id = current_user.
|
| 499 |
|
| 500 |
# Always create a ClientUser entry (user_id is None for anonymous users)
|
| 501 |
new_client_user = ClientUser(
|
| 502 |
-
user_id=server_user_id, # None if anonymous
|
| 503 |
client_user_id=client_user_id,
|
| 504 |
-
|
| 505 |
-
ipv6_address=ipv6_address,
|
| 506 |
device_info={"user_agent": user_agent} if user_agent else None
|
| 507 |
)
|
| 508 |
db.add(new_client_user)
|
|
|
|
| 177 |
"id": item.id,
|
| 178 |
"user_id": item.user_id,
|
| 179 |
"client_user_id": item.client_user_id,
|
| 180 |
+
"ip_address": item.ip_address, # Standardized IP column
|
|
|
|
| 181 |
"device_fingerprint": item.device_fingerprint,
|
| 182 |
"device_info": item.device_info,
|
| 183 |
"created_at": item.created_at.isoformat() if item.created_at else None,
|
|
|
|
| 494 |
country, region = await get_geolocation(ip_address)
|
| 495 |
|
| 496 |
# Determine server user_id (if authenticated)
|
| 497 |
+
server_user_id = current_user.id if current_user else None # Integer FK or None
|
| 498 |
|
| 499 |
# Always create a ClientUser entry (user_id is None for anonymous users)
|
| 500 |
new_client_user = ClientUser(
|
| 501 |
+
user_id=server_user_id, # Integer FK (None if anonymous)
|
| 502 |
client_user_id=client_user_id,
|
| 503 |
+
ip_address=ip_address, # Standardized IP column
|
|
|
|
| 504 |
device_info={"user_agent": user_agent} if user_agent else None
|
| 505 |
)
|
| 506 |
db.add(new_client_user)
|
routers/contact.py
CHANGED
|
@@ -68,7 +68,7 @@ async def submit_contact(
|
|
| 68 |
try:
|
| 69 |
# Create contact record
|
| 70 |
contact = Contact(
|
| 71 |
-
user_id=user.
|
| 72 |
email=user.email,
|
| 73 |
subject=request_body.subject.strip() if request_body.subject else None,
|
| 74 |
message=request_body.message.strip(),
|
|
|
|
| 68 |
try:
|
| 69 |
# Create contact record
|
| 70 |
contact = Contact(
|
| 71 |
+
user_id=user.id, # Integer FK to users.id
|
| 72 |
email=user.email,
|
| 73 |
subject=request_body.subject.strip() if request_body.subject else None,
|
| 74 |
message=request_body.message.strip(),
|
routers/gemini.py
CHANGED
|
@@ -83,7 +83,7 @@ async def create_job(
|
|
| 83 |
|
| 84 |
job = GeminiJob(
|
| 85 |
job_id=job_id,
|
| 86 |
-
user_id=user.
|
| 87 |
job_type=job_type,
|
| 88 |
status="queued",
|
| 89 |
priority=priority,
|
|
@@ -277,14 +277,14 @@ async def get_jobs(
|
|
| 277 |
|
| 278 |
# Query jobs for the current user
|
| 279 |
query = select(GeminiJob).where(
|
| 280 |
-
GeminiJob.user_id == user.
|
| 281 |
).order_by(GeminiJob.created_at.desc()).offset(offset).limit(limit)
|
| 282 |
|
| 283 |
result = await db.execute(query)
|
| 284 |
jobs = result.scalars().all()
|
| 285 |
|
| 286 |
# Get total count
|
| 287 |
-
count_query = select(func.count()).where(GeminiJob.user_id == user.
|
| 288 |
count_result = await db.execute(count_query)
|
| 289 |
total_count = count_result.scalar()
|
| 290 |
|
|
@@ -336,7 +336,7 @@ async def get_job_status(
|
|
| 336 |
"""
|
| 337 |
query = select(GeminiJob).where(
|
| 338 |
GeminiJob.job_id == job_id,
|
| 339 |
-
GeminiJob.user_id == user.
|
| 340 |
)
|
| 341 |
result = await db.execute(query)
|
| 342 |
job = result.scalar_one_or_none()
|
|
@@ -404,7 +404,7 @@ async def download_video(
|
|
| 404 |
|
| 405 |
query = select(GeminiJob).where(
|
| 406 |
GeminiJob.job_id == job_id,
|
| 407 |
-
GeminiJob.user_id == user.
|
| 408 |
GeminiJob.job_type == "video"
|
| 409 |
)
|
| 410 |
result = await db.execute(query)
|
|
@@ -480,7 +480,7 @@ async def cancel_job(
|
|
| 480 |
"""
|
| 481 |
query = select(GeminiJob).where(
|
| 482 |
GeminiJob.job_id == job_id,
|
| 483 |
-
GeminiJob.user_id == user.
|
| 484 |
)
|
| 485 |
result = await db.execute(query)
|
| 486 |
job = result.scalar_one_or_none()
|
|
@@ -522,7 +522,7 @@ async def delete_job(
|
|
| 522 |
"""
|
| 523 |
query = select(GeminiJob).where(
|
| 524 |
GeminiJob.job_id == job_id,
|
| 525 |
-
GeminiJob.user_id == user.
|
| 526 |
)
|
| 527 |
result = await db.execute(query)
|
| 528 |
job = result.scalar_one_or_none()
|
|
|
|
| 83 |
|
| 84 |
job = GeminiJob(
|
| 85 |
job_id=job_id,
|
| 86 |
+
user_id=user.id, # Integer FK to users.id
|
| 87 |
job_type=job_type,
|
| 88 |
status="queued",
|
| 89 |
priority=priority,
|
|
|
|
| 277 |
|
| 278 |
# Query jobs for the current user
|
| 279 |
query = select(GeminiJob).where(
|
| 280 |
+
GeminiJob.user_id == user.id # Integer FK comparison
|
| 281 |
).order_by(GeminiJob.created_at.desc()).offset(offset).limit(limit)
|
| 282 |
|
| 283 |
result = await db.execute(query)
|
| 284 |
jobs = result.scalars().all()
|
| 285 |
|
| 286 |
# Get total count
|
| 287 |
+
count_query = select(func.count()).where(GeminiJob.user_id == user.id) # Integer FK comparison
|
| 288 |
count_result = await db.execute(count_query)
|
| 289 |
total_count = count_result.scalar()
|
| 290 |
|
|
|
|
| 336 |
"""
|
| 337 |
query = select(GeminiJob).where(
|
| 338 |
GeminiJob.job_id == job_id,
|
| 339 |
+
GeminiJob.user_id == user.id # Integer FK comparison
|
| 340 |
)
|
| 341 |
result = await db.execute(query)
|
| 342 |
job = result.scalar_one_or_none()
|
|
|
|
| 404 |
|
| 405 |
query = select(GeminiJob).where(
|
| 406 |
GeminiJob.job_id == job_id,
|
| 407 |
+
GeminiJob.user_id == user.id, # Integer FK comparison
|
| 408 |
GeminiJob.job_type == "video"
|
| 409 |
)
|
| 410 |
result = await db.execute(query)
|
|
|
|
| 480 |
"""
|
| 481 |
query = select(GeminiJob).where(
|
| 482 |
GeminiJob.job_id == job_id,
|
| 483 |
+
GeminiJob.user_id == user.id # Integer FK comparison
|
| 484 |
)
|
| 485 |
result = await db.execute(query)
|
| 486 |
job = result.scalar_one_or_none()
|
|
|
|
| 522 |
"""
|
| 523 |
query = select(GeminiJob).where(
|
| 524 |
GeminiJob.job_id == job_id,
|
| 525 |
+
GeminiJob.user_id == user.id # Integer FK comparison
|
| 526 |
)
|
| 527 |
result = await db.execute(query)
|
| 528 |
job = result.scalar_one_or_none()
|
routers/payments.py
CHANGED
|
@@ -271,7 +271,7 @@ async def create_order(
|
|
| 271 |
# Save transaction to database
|
| 272 |
transaction = PaymentTransaction(
|
| 273 |
transaction_id=transaction_id,
|
| 274 |
-
user_id=user.
|
| 275 |
gateway="razorpay",
|
| 276 |
gateway_order_id=order["id"],
|
| 277 |
package_id=package.id,
|
|
@@ -333,7 +333,7 @@ async def verify_payment(
|
|
| 333 |
result = await db.execute(
|
| 334 |
select(PaymentTransaction).where(
|
| 335 |
PaymentTransaction.gateway_order_id == request.razorpay_order_id,
|
| 336 |
-
PaymentTransaction.user_id == user.
|
| 337 |
)
|
| 338 |
)
|
| 339 |
transaction = result.scalar_one_or_none()
|
|
@@ -487,7 +487,7 @@ async def razorpay_webhook(
|
|
| 487 |
if transaction:
|
| 488 |
# Find user
|
| 489 |
user_result = await db.execute(
|
| 490 |
-
select(User).where(User.
|
| 491 |
)
|
| 492 |
user = user_result.scalar_one_or_none()
|
| 493 |
|
|
@@ -570,7 +570,7 @@ async def get_payment_history(
|
|
| 570 |
# Get total count
|
| 571 |
count_result = await db.execute(
|
| 572 |
select(func.count(PaymentTransaction.id))
|
| 573 |
-
.where(PaymentTransaction.user_id == user.
|
| 574 |
)
|
| 575 |
total_count = count_result.scalar() or 0
|
| 576 |
|
|
@@ -580,7 +580,7 @@ async def get_payment_history(
|
|
| 580 |
# Get paginated transactions
|
| 581 |
result = await db.execute(
|
| 582 |
select(PaymentTransaction)
|
| 583 |
-
.where(PaymentTransaction.user_id == user.
|
| 584 |
.order_by(desc(PaymentTransaction.created_at))
|
| 585 |
.offset(offset)
|
| 586 |
.limit(limit)
|
|
|
|
| 271 |
# Save transaction to database
|
| 272 |
transaction = PaymentTransaction(
|
| 273 |
transaction_id=transaction_id,
|
| 274 |
+
user_id=user.id, # Integer FK to users.id
|
| 275 |
gateway="razorpay",
|
| 276 |
gateway_order_id=order["id"],
|
| 277 |
package_id=package.id,
|
|
|
|
| 333 |
result = await db.execute(
|
| 334 |
select(PaymentTransaction).where(
|
| 335 |
PaymentTransaction.gateway_order_id == request.razorpay_order_id,
|
| 336 |
+
PaymentTransaction.user_id == user.id # Integer FK comparison
|
| 337 |
)
|
| 338 |
)
|
| 339 |
transaction = result.scalar_one_or_none()
|
|
|
|
| 487 |
if transaction:
|
| 488 |
# Find user
|
| 489 |
user_result = await db.execute(
|
| 490 |
+
select(User).where(User.id == transaction.user_id) # Integer FK lookup
|
| 491 |
)
|
| 492 |
user = user_result.scalar_one_or_none()
|
| 493 |
|
|
|
|
| 570 |
# Get total count
|
| 571 |
count_result = await db.execute(
|
| 572 |
select(func.count(PaymentTransaction.id))
|
| 573 |
+
.where(PaymentTransaction.user_id == user.id) # Integer FK comparison
|
| 574 |
)
|
| 575 |
total_count = count_result.scalar() or 0
|
| 576 |
|
|
|
|
| 580 |
# Get paginated transactions
|
| 581 |
result = await db.execute(
|
| 582 |
select(PaymentTransaction)
|
| 583 |
+
.where(PaymentTransaction.user_id == user.id) # Integer FK comparison
|
| 584 |
.order_by(desc(PaymentTransaction.created_at))
|
| 585 |
.offset(offset)
|
| 586 |
.limit(limit)
|
services/credit_service.py
CHANGED
|
@@ -162,7 +162,7 @@ async def refund_credit(session: AsyncSession, job, reason: str) -> bool:
|
|
| 162 |
from core.models import User
|
| 163 |
|
| 164 |
result = await session.execute(
|
| 165 |
-
select(User).where(User.
|
| 166 |
)
|
| 167 |
user = result.scalar_one_or_none()
|
| 168 |
|
|
|
|
| 162 |
from core.models import User
|
| 163 |
|
| 164 |
result = await session.execute(
|
| 165 |
+
select(User).where(User.id == job.user_id)
|
| 166 |
)
|
| 167 |
user = result.scalar_one_or_none()
|
| 168 |
|