rairo commited on
Commit
e6021ca
·
verified ·
1 Parent(s): 484555f

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +136 -48
main.py CHANGED
@@ -132,9 +132,60 @@ def credit_required(cost=1):
132
 
133
 
134
  # Full signup function
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  @app.route('/api/auth/signup', methods=['POST'])
136
  def signup():
137
- if not FIREBASE_INITIALIZED: # Ensure this check is at the top
138
  logging.error("Firebase not initialized. Signup skipped.")
139
  return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 500
140
 
@@ -149,9 +200,12 @@ def signup():
149
  logging.info(f"Backend /signup: Processing request for email: {email}")
150
 
151
  user_record = None
 
 
152
  try:
153
- # Attempt to create the Firebase Auth user.
154
  user_record = auth.create_user(email=email, password=password)
 
155
  logging.info(f"Backend /signup: NEW Firebase Auth user created: {user_record.uid} for email: {email}")
156
  except auth.EmailAlreadyExistsError:
157
  logging.warning(f"Backend /signup: Email {email} already exists in Firebase Auth. Fetching existing user.")
@@ -159,48 +213,46 @@ def signup():
159
  user_record = auth.get_user_by_email(email)
160
  logging.info(f"Backend /signup: Fetched EXISTING Firebase Auth user: {user_record.uid} for email: {email}")
161
  except Exception as e_get:
162
- logging.error(f"Backend /signup: Failed to fetch existing user {email} after EmailAlreadyExistsError: {e_get}")
163
- logging.error(traceback.format_exc())
164
  return jsonify({'error': f'Auth user exists but could not be fetched: {str(e_get)}'}), 500
165
  except Exception as e_create:
166
  logging.error(f"Backend /signup: Error during auth.create_user for {email}: {e_create}")
167
- logging.error(traceback.format_exc())
168
  return jsonify({'error': f'Firebase Auth user creation failed: {str(e_create)}'}), 500
169
 
170
  if not user_record or not user_record.uid:
171
  logging.error(f"Backend /signup: Could not obtain valid user record or UID for {email}.")
172
  return jsonify({'error': 'Failed to establish user authentication identity.'}), 500
173
 
174
- uid_to_use = user_record.uid
175
-
176
- user_ref = db.reference(f'users/{uid_to_use}')
177
 
178
- user_data_to_set = {
179
- 'email': user_record.email,
180
- 'credits': 10,
181
- 'is_admin': False,
182
- 'created_at': datetime.utcnow().isoformat(),
183
- 'suspended': False
184
- }
185
 
186
- logging.info(f"Backend /signup: Attempting to write/overwrite DB profile for UID: {uid_to_use}. Data: {user_data_to_set}")
187
- user_ref.set(user_data_to_set)
188
- logging.info(f"Backend /signup: DB profile set for UID: {uid_to_use} presumed successful.")
 
 
189
 
 
190
 
191
  return jsonify({
192
  'success': True,
193
  'user': {
194
- 'uid': uid_to_use,
195
- **user_data_to_set
196
  }
197
  }), 201
198
 
199
  except Exception as e:
200
- logging.error(f"Backend /signup: UNHANDLED EXCEPTION for email {data.get('email', 'N/A')}: {e}")
201
  logging.error(traceback.format_exc())
202
  return jsonify({'error': f'An unexpected error occurred during signup: {str(e)}'}), 500
203
 
 
204
  @app.route('/api/user/profile', methods=['GET'])
205
  def get_user_profile():
206
  if not FIREBASE_INITIALIZED:
@@ -217,23 +269,26 @@ def get_user_profile():
217
  if not uid:
218
  return jsonify({'error': 'Invalid or expired token'}), 401
219
 
220
- user_data = db.reference(f'users/{uid}').get()
 
221
  if not user_data:
222
- logging.warning(f"User {uid} found in Auth but not in Realtime DB when fetching profile.")
223
- return jsonify({'error': 'User profile not found in database. Please try logging in again.'}), 404
224
 
225
  return jsonify({
226
  'uid': uid,
227
  'email': user_data.get('email'),
228
  'credits': user_data.get('credits', 0),
229
  'is_admin': user_data.get('is_admin', False),
230
- 'suspended': user_data.get('suspended', False) # Include suspended status
231
  })
 
232
  except Exception as e:
233
  logging.error(f"Error fetching user profile: {e}")
 
234
  return jsonify({'error': str(e)}), 500
235
 
236
- # Backend app.py - Full google_signin function
237
  @app.route('/api/auth/google-signin', methods=['POST'])
238
  def google_signin():
239
  if not FIREBASE_INITIALIZED:
@@ -253,34 +308,25 @@ def google_signin():
253
  email = decoded_token.get('email')
254
  logging.info(f"Backend /google-signin: ID token verified. UID: {uid}, Email: {email}")
255
 
256
- user_ref = db.reference(f'users/{uid}')
257
- user_data_from_db = user_ref.get()
258
- final_user_data_for_response = None
 
 
259
 
260
- if not user_data_from_db:
261
- logging.info(f"Backend /google-signin: DB profile for Google user UID {uid} (Email: {email}) not found. Creating new DB profile.")
262
- new_db_profile_data = {
263
- 'email': email,
264
- 'credits': 10,
265
- 'is_admin': False,
266
- 'created_at': datetime.utcnow().isoformat(),
267
- 'suspended': False
268
- }
269
- logging.info(f"Backend /google-signin: Attempting to write NEW DB profile for Google UID: {uid}. Data: {new_db_profile_data}")
270
- user_ref.set(new_db_profile_data)
271
- logging.info(f"Backend /google-signin: DB profile set for Google UID: {uid} presumed successful.")
272
-
273
 
274
- final_user_data_for_response = new_db_profile_data
275
- else:
276
- logging.info(f"Backend /google-signin: Existing DB profile found for Google user UID {uid}. Data: {user_data_from_db}")
277
- final_user_data_for_response = user_data_from_db
278
 
279
  return jsonify({
280
  'success': True,
281
  'user': {
282
  'uid': uid,
283
- **final_user_data_for_response
284
  }
285
  }), 200
286
 
@@ -288,12 +334,54 @@ def google_signin():
288
  logging.error(f"Backend /google-signin: Invalid ID token received.")
289
  return jsonify({'error': 'Invalid ID token.'}), 401
290
  except Exception as e:
291
- # Using 'decoded_token' safely in case it's not defined due to an early error
292
  uid_in_error = decoded_token.get('uid', 'N/A') if 'decoded_token' in locals() and decoded_token else 'N/A'
293
  logging.error(f"Backend /google-signin: UNHANDLED EXCEPTION for UID {uid_in_error}: {e}")
294
  logging.error(traceback.format_exc())
295
  return jsonify({'error': f'An unexpected error occurred during Google Sign-In: {str(e)}'}), 500
296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  @app.route('/api/user/request-credits', methods=['POST'])
298
  @credit_required(cost=0)
299
  def request_credits():
 
132
 
133
 
134
  # Full signup function
135
+ # Add this helper function to verify and repair user profiles
136
+ def ensure_user_profile_exists(uid, email=None):
137
+ """
138
+ Ensures a user profile exists in Realtime DB. Creates one if missing.
139
+ Returns the user data or None if creation fails.
140
+ """
141
+ try:
142
+ user_ref = db.reference(f'users/{uid}')
143
+ user_data = user_ref.get()
144
+
145
+ if not user_data:
146
+ logging.info(f"Creating missing profile for UID: {uid}")
147
+
148
+ # Get email from Firebase Auth if not provided
149
+ if not email:
150
+ try:
151
+ user_record = auth.get_user(uid)
152
+ email = user_record.email
153
+ except Exception as e:
154
+ logging.error(f"Failed to get email for UID {uid}: {e}")
155
+ return None
156
+
157
+ new_profile = {
158
+ 'email': email,
159
+ 'credits': 10,
160
+ 'is_admin': False,
161
+ 'created_at': datetime.utcnow().isoformat(),
162
+ 'suspended': False
163
+ }
164
+
165
+ # Use transaction to ensure atomic write
166
+ def create_profile_transaction(current_data):
167
+ if current_data is None:
168
+ return new_profile
169
+ return current_data # Profile already exists
170
+
171
+ result = user_ref.transaction(create_profile_transaction)
172
+ if result.committed:
173
+ logging.info(f"Successfully created profile for UID: {uid}")
174
+ return new_profile
175
+ else:
176
+ logging.error(f"Failed to create profile for UID: {uid} - transaction not committed")
177
+ return None
178
+
179
+ return user_data
180
+
181
+ except Exception as e:
182
+ logging.error(f"Error ensuring profile exists for UID {uid}: {e}")
183
+ return None
184
+
185
+ # Updated signup function with better error handling
186
  @app.route('/api/auth/signup', methods=['POST'])
187
  def signup():
188
+ if not FIREBASE_INITIALIZED:
189
  logging.error("Firebase not initialized. Signup skipped.")
190
  return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 500
191
 
 
200
  logging.info(f"Backend /signup: Processing request for email: {email}")
201
 
202
  user_record = None
203
+ is_new_user = False
204
+
205
  try:
206
+ # Attempt to create the Firebase Auth user
207
  user_record = auth.create_user(email=email, password=password)
208
+ is_new_user = True
209
  logging.info(f"Backend /signup: NEW Firebase Auth user created: {user_record.uid} for email: {email}")
210
  except auth.EmailAlreadyExistsError:
211
  logging.warning(f"Backend /signup: Email {email} already exists in Firebase Auth. Fetching existing user.")
 
213
  user_record = auth.get_user_by_email(email)
214
  logging.info(f"Backend /signup: Fetched EXISTING Firebase Auth user: {user_record.uid} for email: {email}")
215
  except Exception as e_get:
216
+ logging.error(f"Backend /signup: Failed to fetch existing user {email}: {e_get}")
 
217
  return jsonify({'error': f'Auth user exists but could not be fetched: {str(e_get)}'}), 500
218
  except Exception as e_create:
219
  logging.error(f"Backend /signup: Error during auth.create_user for {email}: {e_create}")
 
220
  return jsonify({'error': f'Firebase Auth user creation failed: {str(e_create)}'}), 500
221
 
222
  if not user_record or not user_record.uid:
223
  logging.error(f"Backend /signup: Could not obtain valid user record or UID for {email}.")
224
  return jsonify({'error': 'Failed to establish user authentication identity.'}), 500
225
 
226
+ uid = user_record.uid
 
 
227
 
228
+ # Ensure profile exists in Realtime DB
229
+ user_data = ensure_user_profile_exists(uid, user_record.email)
230
+ if not user_data:
231
+ logging.error(f"Backend /signup: Failed to create/verify DB profile for UID: {uid}")
232
+ return jsonify({'error': 'Failed to create user profile in database.'}), 500
 
 
233
 
234
+ # Verify the profile was actually written
235
+ verification_data = db.reference(f'users/{uid}').get()
236
+ if not verification_data:
237
+ logging.error(f"Backend /signup: Profile verification failed for UID: {uid}")
238
+ return jsonify({'error': 'User profile creation could not be verified.'}), 500
239
 
240
+ logging.info(f"Backend /signup: Profile verified for UID: {uid}")
241
 
242
  return jsonify({
243
  'success': True,
244
  'user': {
245
+ 'uid': uid,
246
+ **user_data
247
  }
248
  }), 201
249
 
250
  except Exception as e:
251
+ logging.error(f"Backend /signup: UNHANDLED EXCEPTION: {e}")
252
  logging.error(traceback.format_exc())
253
  return jsonify({'error': f'An unexpected error occurred during signup: {str(e)}'}), 500
254
 
255
+ # Updated profile endpoint with auto-repair
256
  @app.route('/api/user/profile', methods=['GET'])
257
  def get_user_profile():
258
  if not FIREBASE_INITIALIZED:
 
269
  if not uid:
270
  return jsonify({'error': 'Invalid or expired token'}), 401
271
 
272
+ # Try to get user data, create if missing
273
+ user_data = ensure_user_profile_exists(uid)
274
  if not user_data:
275
+ logging.error(f"Failed to get/create profile for UID: {uid}")
276
+ return jsonify({'error': 'Unable to retrieve or create user profile. Please contact support.'}), 500
277
 
278
  return jsonify({
279
  'uid': uid,
280
  'email': user_data.get('email'),
281
  'credits': user_data.get('credits', 0),
282
  'is_admin': user_data.get('is_admin', False),
283
+ 'suspended': user_data.get('suspended', False)
284
  })
285
+
286
  except Exception as e:
287
  logging.error(f"Error fetching user profile: {e}")
288
+ logging.error(traceback.format_exc())
289
  return jsonify({'error': str(e)}), 500
290
 
291
+ # Updated Google Sign-In with better error handling
292
  @app.route('/api/auth/google-signin', methods=['POST'])
293
  def google_signin():
294
  if not FIREBASE_INITIALIZED:
 
308
  email = decoded_token.get('email')
309
  logging.info(f"Backend /google-signin: ID token verified. UID: {uid}, Email: {email}")
310
 
311
+ # Ensure profile exists in Realtime DB
312
+ user_data = ensure_user_profile_exists(uid, email)
313
+ if not user_data:
314
+ logging.error(f"Backend /google-signin: Failed to create/verify DB profile for UID: {uid}")
315
+ return jsonify({'error': 'Failed to create user profile in database.'}), 500
316
 
317
+ # Double-check the profile exists
318
+ verification_data = db.reference(f'users/{uid}').get()
319
+ if not verification_data:
320
+ logging.error(f"Backend /google-signin: Profile verification failed for UID: {uid}")
321
+ return jsonify({'error': 'User profile creation could not be verified.'}), 500
 
 
 
 
 
 
 
 
322
 
323
+ logging.info(f"Backend /google-signin: Profile verified for UID: {uid}")
 
 
 
324
 
325
  return jsonify({
326
  'success': True,
327
  'user': {
328
  'uid': uid,
329
+ **user_data
330
  }
331
  }), 200
332
 
 
334
  logging.error(f"Backend /google-signin: Invalid ID token received.")
335
  return jsonify({'error': 'Invalid ID token.'}), 401
336
  except Exception as e:
 
337
  uid_in_error = decoded_token.get('uid', 'N/A') if 'decoded_token' in locals() and decoded_token else 'N/A'
338
  logging.error(f"Backend /google-signin: UNHANDLED EXCEPTION for UID {uid_in_error}: {e}")
339
  logging.error(traceback.format_exc())
340
  return jsonify({'error': f'An unexpected error occurred during Google Sign-In: {str(e)}'}), 500
341
 
342
+ # Add this endpoint to repair existing broken profiles
343
+ @app.route('/api/admin/repair-profiles', methods=['POST'])
344
+ def repair_profiles():
345
+ """Admin endpoint to repair missing user profiles"""
346
+ if not FIREBASE_INITIALIZED:
347
+ return jsonify({'error': 'Firebase not initialized'}), 500
348
+
349
+ try:
350
+ # Get all users from Firebase Auth
351
+ page = auth.list_users()
352
+ repaired_count = 0
353
+ failed_count = 0
354
+
355
+ while page:
356
+ for user in page.users:
357
+ uid = user.uid
358
+ email = user.email
359
+
360
+ # Check if profile exists in DB
361
+ user_data = db.reference(f'users/{uid}').get()
362
+ if not user_data:
363
+ logging.info(f"Repairing missing profile for UID: {uid}, Email: {email}")
364
+ repaired_data = ensure_user_profile_exists(uid, email)
365
+ if repaired_data:
366
+ repaired_count += 1
367
+ logging.info(f"Successfully repaired profile for UID: {uid}")
368
+ else:
369
+ failed_count += 1
370
+ logging.error(f"Failed to repair profile for UID: {uid}")
371
+
372
+ # Get next batch
373
+ page = page.get_next_page()
374
+
375
+ return jsonify({
376
+ 'success': True,
377
+ 'repaired': repaired_count,
378
+ 'failed': failed_count
379
+ })
380
+
381
+ except Exception as e:
382
+ logging.error(f"Error repairing profiles: {e}")
383
+ return jsonify({'error': str(e)}), 500
384
+
385
  @app.route('/api/user/request-credits', methods=['POST'])
386
  @credit_required(cost=0)
387
  def request_credits():