Spaces:
Sleeping
Sleeping
Update main.py
Browse files
main.py
CHANGED
|
@@ -57,9 +57,6 @@ except Exception as e:
|
|
| 57 |
print(f"Error initializing Firebase: {e}")
|
| 58 |
|
| 59 |
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
bucket = storage.bucket()
|
| 64 |
|
| 65 |
|
|
@@ -233,6 +230,49 @@ def upload_log():
|
|
| 233 |
logging.error(f"❌ ERROR: Failed to upload log file: {e}")
|
| 234 |
return None
|
| 235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
|
| 237 |
# -----------------------
|
| 238 |
# Content
|
|
@@ -1368,7 +1408,67 @@ def admin_list_stories():
|
|
| 1368 |
except Exception as e:
|
| 1369 |
return jsonify({'error': str(e)}), 500
|
| 1370 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1371 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1372 |
# ---------- Admin Endpoint to Directly Update Credits ----------
|
| 1373 |
@app.route('/api/admin/users/<string:uid>/credits', methods=['PUT'])
|
| 1374 |
def admin_update_credits(uid):
|
|
|
|
| 57 |
print(f"Error initializing Firebase: {e}")
|
| 58 |
|
| 59 |
|
|
|
|
|
|
|
|
|
|
| 60 |
bucket = storage.bucket()
|
| 61 |
|
| 62 |
|
|
|
|
| 230 |
logging.error(f"❌ ERROR: Failed to upload log file: {e}")
|
| 231 |
return None
|
| 232 |
|
| 233 |
+
@app.route('/api/feedback', methods=['POST'])
|
| 234 |
+
def submit_feedback():
|
| 235 |
+
"""
|
| 236 |
+
Allows a user to submit feedback, bug reports, or feature requests.
|
| 237 |
+
"""
|
| 238 |
+
try:
|
| 239 |
+
# --- Authentication ---
|
| 240 |
+
auth_header = request.headers.get('Authorization', '')
|
| 241 |
+
if not auth_header.startswith('Bearer '):
|
| 242 |
+
return jsonify({'error': 'Missing or invalid token'}), 401
|
| 243 |
+
token = auth_header.split(' ')[1]
|
| 244 |
+
uid = verify_token(token)
|
| 245 |
+
if not uid:
|
| 246 |
+
return jsonify({'error': 'Invalid or expired token'}), 401
|
| 247 |
+
|
| 248 |
+
# --- Parse Feedback Data ---
|
| 249 |
+
data = request.get_json()
|
| 250 |
+
feedback_type = data.get('type', 'general') # e.g. "bug", "feature_request", "general"
|
| 251 |
+
message = data.get('message')
|
| 252 |
+
if not message:
|
| 253 |
+
return jsonify({'error': 'message is required'}), 400
|
| 254 |
+
|
| 255 |
+
# Optionally, store some user info like email or name
|
| 256 |
+
user_data = db.reference(f'users/{uid}').get() or {}
|
| 257 |
+
user_email = user_data.get('email', 'unknown')
|
| 258 |
+
|
| 259 |
+
# Create a new feedback entry in "feedback" node
|
| 260 |
+
feedback_id = str(uuid.uuid4())
|
| 261 |
+
feedback_ref = db.reference(f'feedback/{feedback_id}')
|
| 262 |
+
feedback_record = {
|
| 263 |
+
"user_id": uid,
|
| 264 |
+
"user_email": user_email,
|
| 265 |
+
"type": feedback_type,
|
| 266 |
+
"message": message,
|
| 267 |
+
"created_at": datetime.utcnow().isoformat(),
|
| 268 |
+
"status": "open" # admin can mark "resolved" or "in progress"
|
| 269 |
+
}
|
| 270 |
+
feedback_ref.set(feedback_record)
|
| 271 |
+
|
| 272 |
+
return jsonify({"success": True, "feedback_id": feedback_id}), 201
|
| 273 |
+
|
| 274 |
+
except Exception as e:
|
| 275 |
+
return jsonify({'error': str(e)}), 500
|
| 276 |
|
| 277 |
# -----------------------
|
| 278 |
# Content
|
|
|
|
| 1408 |
except Exception as e:
|
| 1409 |
return jsonify({'error': str(e)}), 500
|
| 1410 |
|
| 1411 |
+
@app.route('/api/admin/notifications', methods=['POST'])
|
| 1412 |
+
def send_notifications():
|
| 1413 |
+
"""
|
| 1414 |
+
Admin sends notifications to one, multiple, or all users.
|
| 1415 |
+
"""
|
| 1416 |
+
try:
|
| 1417 |
+
# 1) Verify admin
|
| 1418 |
+
admin_uid = verify_admin(request.headers.get('Authorization', ''))
|
| 1419 |
+
if not admin_uid:
|
| 1420 |
+
return jsonify({'error': 'Unauthorized: Admin access required'}), 401
|
| 1421 |
|
| 1422 |
+
# 2) Parse request data
|
| 1423 |
+
data = request.get_json()
|
| 1424 |
+
message = data.get('message')
|
| 1425 |
+
if not message:
|
| 1426 |
+
return jsonify({'error': 'message is required'}), 400
|
| 1427 |
+
|
| 1428 |
+
# 'recipients' can be a single user_id, a list of user_ids, or "all"
|
| 1429 |
+
recipients = data.get('recipients', "all")
|
| 1430 |
+
|
| 1431 |
+
# 3) If recipients == "all", get all user IDs
|
| 1432 |
+
all_users_ref = db.reference('users')
|
| 1433 |
+
all_users_data = all_users_ref.get() or {}
|
| 1434 |
+
|
| 1435 |
+
user_ids_to_notify = []
|
| 1436 |
+
|
| 1437 |
+
if recipients == "all":
|
| 1438 |
+
user_ids_to_notify = list(all_users_data.keys())
|
| 1439 |
+
elif isinstance(recipients, list):
|
| 1440 |
+
# Filter out invalid user IDs
|
| 1441 |
+
user_ids_to_notify = [uid for uid in recipients if uid in all_users_data]
|
| 1442 |
+
elif isinstance(recipients, str):
|
| 1443 |
+
# Could be a single user_id if not "all"
|
| 1444 |
+
if recipients in all_users_data:
|
| 1445 |
+
user_ids_to_notify = [recipients]
|
| 1446 |
+
else:
|
| 1447 |
+
return jsonify({'error': 'Invalid single user_id'}), 400
|
| 1448 |
+
else:
|
| 1449 |
+
return jsonify({'error': 'recipients must be "all", a user_id, or a list of user_ids'}), 400
|
| 1450 |
+
|
| 1451 |
+
# 4) Create a "notifications" node for each user
|
| 1452 |
+
# E.g., notifications/{user_id}/{notification_id}
|
| 1453 |
+
now_str = datetime.utcnow().isoformat()
|
| 1454 |
+
for user_id in user_ids_to_notify:
|
| 1455 |
+
notif_id = str(uuid.uuid4())
|
| 1456 |
+
notif_ref = db.reference(f'notifications/{user_id}/{notif_id}')
|
| 1457 |
+
notif_data = {
|
| 1458 |
+
"from_admin": admin_uid,
|
| 1459 |
+
"message": message,
|
| 1460 |
+
"created_at": now_str,
|
| 1461 |
+
"read": False
|
| 1462 |
+
}
|
| 1463 |
+
notif_ref.set(notif_data)
|
| 1464 |
+
|
| 1465 |
+
return jsonify({
|
| 1466 |
+
'success': True,
|
| 1467 |
+
'message': f"Notification sent to {len(user_ids_to_notify)} user(s)."
|
| 1468 |
+
}), 200
|
| 1469 |
+
|
| 1470 |
+
except Exception as e:
|
| 1471 |
+
return jsonify({'error': str(e)}), 500
|
| 1472 |
# ---------- Admin Endpoint to Directly Update Credits ----------
|
| 1473 |
@app.route('/api/admin/users/<string:uid>/credits', methods=['PUT'])
|
| 1474 |
def admin_update_credits(uid):
|