Cuong2004 commited on
Commit
b5482e9
·
1 Parent(s): 8db59e5
Files changed (2) hide show
  1. app/auth/controls.py +48 -21
  2. app/itineraries/router.py +50 -35
app/auth/controls.py CHANGED
@@ -78,14 +78,12 @@ async def login_control(access_token: str, db: AsyncSession) -> dict:
78
  detail="Email not provided by Google"
79
  )
80
 
81
- # Check if user exists
82
  result = await db.execute(
83
  text("""
84
- SELECT id, full_name, avatar_url, role
85
- FROM profiles
86
- WHERE id = (
87
- SELECT id FROM auth.users WHERE email = :email
88
- )
89
  """),
90
  {"email": email}
91
  )
@@ -106,28 +104,57 @@ async def login_control(access_token: str, db: AsyncSession) -> dict:
106
  )
107
  await db.commit()
108
  else:
109
- # Create new user
110
- user_id = str(uuid4())
111
 
112
- # Create auth.users entry (assuming Supabase-like schema)
113
- await db.execute(
114
- text("""
115
- INSERT INTO auth.users (id, email, created_at)
116
- VALUES (:id, :email, NOW())
117
- ON CONFLICT (email) DO UPDATE SET email = :email
118
- RETURNING id
119
- """),
120
- {"id": user_id, "email": email}
121
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
- # Create profile
124
  await db.execute(
125
  text("""
126
- INSERT INTO profiles (id, full_name, avatar_url, role, locale, created_at, updated_at)
127
- VALUES (:id, :full_name, :avatar_url, 'tourist', 'vi_VN', NOW(), NOW())
 
 
128
  """),
129
  {
130
  "id": user_id,
 
131
  "full_name": full_name,
132
  "avatar_url": avatar_url
133
  }
 
78
  detail="Email not provided by Google"
79
  )
80
 
81
+ # Check if user exists by email in profiles table
82
  result = await db.execute(
83
  text("""
84
+ SELECT p.id, p.full_name, p.avatar_url, p.role, p.email
85
+ FROM profiles p
86
+ WHERE p.email = :email
 
 
87
  """),
88
  {"email": email}
89
  )
 
104
  )
105
  await db.commit()
106
  else:
107
+ # Create new user using Supabase Admin API
108
+ from app.shared.integrations.supabase_client import supabase
109
 
110
+ try:
111
+ # Create user in auth.users using Supabase Admin API
112
+ auth_response = supabase.auth.admin.create_user({
113
+ "email": email,
114
+ "email_confirm": True, # Auto-confirm email for OAuth users
115
+ "user_metadata": {
116
+ "full_name": full_name,
117
+ "avatar_url": avatar_url,
118
+ "provider": "google"
119
+ }
120
+ })
121
+
122
+ user_id = auth_response.user.id
123
+
124
+ except Exception as e:
125
+ # If user already exists in auth.users, try to get their ID
126
+ try:
127
+ # Query auth.users to get existing user
128
+ auth_result = await db.execute(
129
+ text("SELECT id FROM auth.users WHERE email = :email"),
130
+ {"email": email}
131
+ )
132
+ auth_row = auth_result.fetchone()
133
+
134
+ if auth_row:
135
+ user_id = str(auth_row.id)
136
+ else:
137
+ raise HTTPException(
138
+ status_code=500,
139
+ detail=f"Failed to create or retrieve user: {str(e)}"
140
+ )
141
+ except Exception as inner_e:
142
+ raise HTTPException(
143
+ status_code=500,
144
+ detail=f"Failed to create user: {str(e)}, {str(inner_e)}"
145
+ )
146
 
147
+ # Create profile in profiles table
148
  await db.execute(
149
  text("""
150
+ INSERT INTO profiles (id, email, full_name, avatar_url, role, locale, created_at, updated_at)
151
+ VALUES (:id, :email, :full_name, :avatar_url, 'tourist', 'vi_VN', NOW(), NOW())
152
+ ON CONFLICT (id) DO UPDATE
153
+ SET email = :email, full_name = :full_name, avatar_url = :avatar_url, updated_at = NOW()
154
  """),
155
  {
156
  "id": user_id,
157
+ "email": email,
158
  "full_name": full_name,
159
  "avatar_url": avatar_url
160
  }
app/itineraries/router.py CHANGED
@@ -336,42 +336,57 @@ async def add_stop(
336
  # Get place snapshot - prefer from request, otherwise from DB
337
  snapshot = request.snapshot
338
  if not snapshot:
339
- # Try to fetch from database
340
- place_result = await db.execute(
341
- text("SELECT name, category, address, rating FROM places_metadata WHERE place_id = :place_id"),
342
- {"place_id": request.place_id}
343
- )
344
- place_row = place_result.fetchone()
345
- if place_row:
346
- snapshot = {
347
- "name": place_row.name,
348
- "category": place_row.category,
349
- "address": place_row.address,
350
- "rating": float(place_row.rating) if place_row.rating else None,
351
- }
 
 
 
 
352
 
353
-
354
- # Insert stop
355
- result = await db.execute(
356
- text("""
357
- INSERT INTO itinerary_stops (itinerary_id, day_index, order_index, place_id, arrival_time, stay_minutes, notes, tags, snapshot)
358
- VALUES (:itinerary_id, :day_index, :order_index, :place_id, :arrival_time, :stay_minutes, :notes, :tags, :snapshot)
359
- RETURNING id, itinerary_id, day_index, order_index, place_id, arrival_time, stay_minutes, notes, tags, snapshot, created_at, updated_at
360
- """),
361
- {
362
- "itinerary_id": itinerary_id,
363
- "day_index": request.day_index,
364
- "order_index": request.order_index,
365
- "place_id": request.place_id,
366
- "arrival_time": request.arrival_time,
367
- "stay_minutes": request.stay_minutes,
368
- "notes": request.notes,
369
- "tags": request.tags,
370
- "snapshot": snapshot,
371
- }
372
- )
373
- await db.commit()
374
- row = result.fetchone()
 
 
 
 
 
 
 
 
 
 
 
375
 
376
  stop = Stop(
377
  id=str(row.id),
 
336
  # Get place snapshot - prefer from request, otherwise from DB
337
  snapshot = request.snapshot
338
  if not snapshot:
339
+ # Try to fetch from database (optional - don't fail if not found)
340
+ try:
341
+ place_result = await db.execute(
342
+ text("SELECT name, category, address, rating FROM places_metadata WHERE place_id = :place_id"),
343
+ {"place_id": request.place_id}
344
+ )
345
+ place_row = place_result.fetchone()
346
+ if place_row:
347
+ snapshot = {
348
+ "name": place_row.name,
349
+ "category": place_row.category,
350
+ "address": place_row.address,
351
+ "rating": float(place_row.rating) if place_row.rating else None,
352
+ }
353
+ except Exception as e:
354
+ # Log but don't fail - snapshot is optional
355
+ print(f"Warning: Could not fetch place metadata for {request.place_id}: {e}")
356
 
357
+ try:
358
+ # Insert stop
359
+ result = await db.execute(
360
+ text("""
361
+ INSERT INTO itinerary_stops (itinerary_id, day_index, order_index, place_id, arrival_time, stay_minutes, notes, tags, snapshot)
362
+ VALUES (:itinerary_id, :day_index, :order_index, :place_id, :arrival_time, :stay_minutes, :notes, :tags, :snapshot)
363
+ RETURNING id, itinerary_id, day_index, order_index, place_id, arrival_time, stay_minutes, notes, tags, snapshot, created_at, updated_at
364
+ """),
365
+ {
366
+ "itinerary_id": itinerary_id,
367
+ "day_index": request.day_index,
368
+ "order_index": request.order_index,
369
+ "place_id": request.place_id,
370
+ "arrival_time": request.arrival_time,
371
+ "stay_minutes": request.stay_minutes,
372
+ "notes": request.notes,
373
+ "tags": request.tags,
374
+ "snapshot": snapshot,
375
+ }
376
+ )
377
+ await db.commit()
378
+ row = result.fetchone()
379
+ except Exception as e:
380
+ # Rollback and provide detailed error
381
+ await db.rollback()
382
+ error_msg = str(e)
383
+ print(f"❌ Database error adding stop: {error_msg}")
384
+ print(f" place_id: {request.place_id}")
385
+ print(f" snapshot: {snapshot}")
386
+ raise HTTPException(
387
+ status_code=500,
388
+ detail=f"Database error: {error_msg}"
389
+ )
390
 
391
  stop = Stop(
392
  id=str(row.id),