Spaces:
Sleeping
Sleeping
Update main.py
Browse files
main.py
CHANGED
|
@@ -1266,9 +1266,182 @@ def admin_get_all_deals():
|
|
| 1266 |
return handle_route_errors(e, uid_context=admin_uid)
|
| 1267 |
# --- END OF ADMIN ALL LISTINGS/DEALS ---
|
| 1268 |
|
|
|
|
| 1269 |
|
| 1270 |
-
|
| 1271 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1272 |
|
| 1273 |
@app.route('/api/admin/deals/pending', methods=['GET'])
|
| 1274 |
def admin_get_pending_deals():
|
|
|
|
| 1266 |
return handle_route_errors(e, uid_context=admin_uid)
|
| 1267 |
# --- END OF ADMIN ALL LISTINGS/DEALS ---
|
| 1268 |
|
| 1269 |
+
# --- ADMIN ENDPOINTS FOR WHATSAPP-MANAGED FARMER ACCOUNTS ---
|
| 1270 |
|
| 1271 |
+
@app.route('/api/admin/whatsapp-farmers/create', methods=['POST'])
|
| 1272 |
+
def admin_create_whatsapp_farmer():
|
| 1273 |
+
auth_header = request.headers.get('Authorization')
|
| 1274 |
+
admin_uid = None
|
| 1275 |
+
try:
|
| 1276 |
+
admin_uid = verify_admin(auth_header)
|
| 1277 |
+
if not FIREBASE_INITIALIZED:
|
| 1278 |
+
return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
|
| 1279 |
+
|
| 1280 |
+
data = request.get_json()
|
| 1281 |
+
name = data.get('name')
|
| 1282 |
+
phone_number = data.get('phone_number') # Expecting E.164 format ideally
|
| 1283 |
+
location = data.get('location', "")
|
| 1284 |
+
initial_notes = data.get('initial_notes', "")
|
| 1285 |
+
|
| 1286 |
+
if not name or not phone_number:
|
| 1287 |
+
return jsonify({'error': 'Farmer name and phone number are required.'}), 400
|
| 1288 |
+
|
| 1289 |
+
# Basic validation for phone number format (can be enhanced)
|
| 1290 |
+
if not re.match(r"^\+?[1-9]\d{1,14}$", phone_number):
|
| 1291 |
+
return jsonify({'error': 'Invalid phone number format. Please use E.164 like +263771234567.'}), 400
|
| 1292 |
+
|
| 1293 |
+
# Check if phone number is already in use by a fully registered webapp user
|
| 1294 |
+
# This query can be slow if you have many users. Consider indexing phone_number.
|
| 1295 |
+
users_ref = db.reference('users', app=db_app)
|
| 1296 |
+
existing_user_query = users_ref.order_by_child('phone_number').equal_to(phone_number).limit_to_first(1).get()
|
| 1297 |
+
if existing_user_query:
|
| 1298 |
+
for existing_uid, existing_user_data in existing_user_query.items():
|
| 1299 |
+
if existing_user_data.get('account_type') == 'webapp_registered':
|
| 1300 |
+
return jsonify({'error': f'This phone number is already registered to a web app user (UID: {existing_uid}).'}), 409
|
| 1301 |
+
# Optionally, handle if already a whatsapp_managed account with this number
|
| 1302 |
+
# if existing_user_data.get('account_type') == 'whatsapp_managed':
|
| 1303 |
+
# return jsonify({'error': f'This phone number is already managed for another WhatsApp farmer (UID: {existing_uid}).'}), 409
|
| 1304 |
+
|
| 1305 |
+
|
| 1306 |
+
# Generate a unique ID for this WhatsApp-managed farmer
|
| 1307 |
+
# This UID will be used in the 'users' node. No Firebase Auth user created at this stage.
|
| 1308 |
+
farmer_uid = f"wpfarmer_{str(uuid.uuid4())}"
|
| 1309 |
+
|
| 1310 |
+
profile_data = {
|
| 1311 |
+
'uid': farmer_uid, # Store the UID within the profile too for convenience
|
| 1312 |
+
'name': name,
|
| 1313 |
+
'phone_number': phone_number,
|
| 1314 |
+
'email': f"{farmer_uid}@whatsapp.tunasonga.internal", # Placeholder email
|
| 1315 |
+
'location': location,
|
| 1316 |
+
'roles': {'farmer': True, 'buyer': False, 'transporter': False},
|
| 1317 |
+
'account_type': "whatsapp_managed",
|
| 1318 |
+
'is_placeholder_account': True, # Indicates this was admin-created before web registration
|
| 1319 |
+
'can_login_webapp': False, # Cannot log in to web app yet
|
| 1320 |
+
'managed_by_admin_uid': admin_uid,
|
| 1321 |
+
'created_at': datetime.now(timezone.utc).isoformat(),
|
| 1322 |
+
'created_by_admin_uid': admin_uid, # Explicitly track creator
|
| 1323 |
+
'whatsapp_interaction_log': [{ # Start a log
|
| 1324 |
+
'timestamp': datetime.now(timezone.utc).isoformat(),
|
| 1325 |
+
'action': 'account_created_by_admin',
|
| 1326 |
+
'admin_uid': admin_uid,
|
| 1327 |
+
'notes': f"Initial notes: {initial_notes}" if initial_notes else "Account created."
|
| 1328 |
+
}]
|
| 1329 |
+
}
|
| 1330 |
+
|
| 1331 |
+
db.reference(f'users/{farmer_uid}', app=db_app).set(profile_data)
|
| 1332 |
+
|
| 1333 |
+
return jsonify({
|
| 1334 |
+
'success': True,
|
| 1335 |
+
'message': f'WhatsApp-managed farmer account created for {name} ({phone_number}).',
|
| 1336 |
+
'farmer_uid': farmer_uid,
|
| 1337 |
+
'profile': profile_data
|
| 1338 |
+
}), 201
|
| 1339 |
+
|
| 1340 |
+
except Exception as e:
|
| 1341 |
+
return handle_route_errors(e, uid_context=admin_uid)
|
| 1342 |
+
|
| 1343 |
+
|
| 1344 |
+
@app.route('/api/admin/whatsapp-farmers', methods=['GET'])
|
| 1345 |
+
def admin_list_whatsapp_farmers():
|
| 1346 |
+
auth_header = request.headers.get('Authorization')
|
| 1347 |
+
admin_uid = None
|
| 1348 |
+
try:
|
| 1349 |
+
admin_uid = verify_admin(auth_header)
|
| 1350 |
+
if not FIREBASE_INITIALIZED:
|
| 1351 |
+
return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
|
| 1352 |
+
|
| 1353 |
+
users_ref = db.reference('users', app=db_app)
|
| 1354 |
+
# Querying for account_type. This requires an index on 'account_type' in Firebase rules for performance.
|
| 1355 |
+
# ".indexOn": ["account_type"] under your "users" rules.
|
| 1356 |
+
whatsapp_farmers_query = users_ref.order_by_child('account_type').equal_to('whatsapp_managed').get()
|
| 1357 |
+
|
| 1358 |
+
whatsapp_farmers = whatsapp_farmers_query or {}
|
| 1359 |
+
|
| 1360 |
+
return jsonify(whatsapp_farmers), 200
|
| 1361 |
+
|
| 1362 |
+
except Exception as e:
|
| 1363 |
+
return handle_route_errors(e, uid_context=admin_uid)
|
| 1364 |
+
|
| 1365 |
+
@app.route('/api/admin/whatsapp-farmers/<farmer_uid>', methods=['GET'])
|
| 1366 |
+
def admin_get_whatsapp_farmer(farmer_uid):
|
| 1367 |
+
auth_header = request.headers.get('Authorization')
|
| 1368 |
+
admin_uid = None
|
| 1369 |
+
try:
|
| 1370 |
+
admin_uid = verify_admin(auth_header)
|
| 1371 |
+
if not FIREBASE_INITIALIZED:
|
| 1372 |
+
return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
|
| 1373 |
+
|
| 1374 |
+
farmer_ref = db.reference(f'users/{farmer_uid}', app=db_app)
|
| 1375 |
+
farmer_data = farmer_ref.get()
|
| 1376 |
+
|
| 1377 |
+
if not farmer_data or farmer_data.get('account_type') != 'whatsapp_managed':
|
| 1378 |
+
return jsonify({'error': 'WhatsApp-managed farmer not found or not of correct type.'}), 404
|
| 1379 |
+
|
| 1380 |
+
return jsonify(farmer_data), 200
|
| 1381 |
+
|
| 1382 |
+
except Exception as e:
|
| 1383 |
+
return handle_route_errors(e, uid_context=admin_uid)
|
| 1384 |
+
|
| 1385 |
+
|
| 1386 |
+
@app.route('/api/admin/whatsapp-farmers/<farmer_uid>/update', methods=['PUT'])
|
| 1387 |
+
def admin_update_whatsapp_farmer(farmer_uid):
|
| 1388 |
+
auth_header = request.headers.get('Authorization')
|
| 1389 |
+
admin_uid = None
|
| 1390 |
+
try:
|
| 1391 |
+
admin_uid = verify_admin(auth_header)
|
| 1392 |
+
if not FIREBASE_INITIALIZED:
|
| 1393 |
+
return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
|
| 1394 |
+
|
| 1395 |
+
farmer_ref = db.reference(f'users/{farmer_uid}', app=db_app)
|
| 1396 |
+
farmer_data = farmer_ref.get()
|
| 1397 |
+
|
| 1398 |
+
if not farmer_data or farmer_data.get('account_type') != 'whatsapp_managed':
|
| 1399 |
+
return jsonify({'error': 'WhatsApp-managed farmer not found or not of correct type.'}), 404
|
| 1400 |
+
|
| 1401 |
+
data = request.get_json()
|
| 1402 |
+
updates = {}
|
| 1403 |
+
allowed_fields_to_update = ['name', 'location', 'phone_number'] # Define what admin can change
|
| 1404 |
+
|
| 1405 |
+
for field in allowed_fields_to_update:
|
| 1406 |
+
if field in data:
|
| 1407 |
+
updates[field] = data[field]
|
| 1408 |
+
|
| 1409 |
+
if not updates and 'additional_notes' not in data : # Check if any valid fields or notes are provided
|
| 1410 |
+
return jsonify({'error': 'No valid fields to update or notes provided.'}), 400
|
| 1411 |
+
|
| 1412 |
+
# Log the update action
|
| 1413 |
+
if data.get('additional_notes'):
|
| 1414 |
+
log_entry_key = db.reference(f'users/{farmer_uid}/whatsapp_interaction_log', app=db_app).push().key
|
| 1415 |
+
log_entry = {
|
| 1416 |
+
'timestamp': datetime.now(timezone.utc).isoformat(),
|
| 1417 |
+
'action': 'admin_update_notes',
|
| 1418 |
+
'admin_uid': admin_uid,
|
| 1419 |
+
'notes': data.get('additional_notes')
|
| 1420 |
+
}
|
| 1421 |
+
# To add to the log, we need to fetch existing logs or use a transaction if it's critical
|
| 1422 |
+
# For simplicity here, we'll just push a new entry.
|
| 1423 |
+
# If you want to update the main profile and add a log entry atomically,
|
| 1424 |
+
# you'd construct a single update payload for farmer_ref.update()
|
| 1425 |
+
db.reference(f'users/{farmer_uid}/whatsapp_interaction_log/{log_entry_key}', app=db_app).set(log_entry)
|
| 1426 |
+
|
| 1427 |
+
|
| 1428 |
+
if updates: # If there are profile fields to update
|
| 1429 |
+
updates['last_updated_by_admin_uid'] = admin_uid
|
| 1430 |
+
updates['last_updated_at'] = datetime.now(timezone.utc).isoformat()
|
| 1431 |
+
farmer_ref.update(updates)
|
| 1432 |
+
|
| 1433 |
+
updated_farmer_data = farmer_ref.get() # Get the latest data
|
| 1434 |
+
|
| 1435 |
+
return jsonify({
|
| 1436 |
+
'success': True,
|
| 1437 |
+
'message': f'WhatsApp-managed farmer {farmer_uid} updated.',
|
| 1438 |
+
'profile': updated_farmer_data
|
| 1439 |
+
}), 200
|
| 1440 |
+
|
| 1441 |
+
except Exception as e:
|
| 1442 |
+
return handle_route_errors(e, uid_context=admin_uid)
|
| 1443 |
+
|
| 1444 |
+
# --- END OF WHATSAPP-MANAGED FARMER ACCOUNT ENDPOINTS ---
|
| 1445 |
|
| 1446 |
@app.route('/api/admin/deals/pending', methods=['GET'])
|
| 1447 |
def admin_get_pending_deals():
|